blob: 2b56b74dad844a6daa1ef647b1ece40bdd0f2705 [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
bungeman99fe8222015-08-20 07:57:51 -0700108 static_assert(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, "need_to_be_in_sync");
robertphillips@google.come37ad352013-03-01 19:44:30 +0000109 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
110
111 int overflow = 0;
112 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
113 // This op's size overflows so an extra uint32_t will be written
114 // after the op code
115 overflow = sizeof(uint32_t);
116 }
117
118 if (SAVE_LAYER == op) {
119 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
120 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
121
122 if (kSaveLayerNoBoundsSize == opSize) {
123 return kSaveLayerNoBoundsPaintOffset + overflow;
124 } else {
125 SkASSERT(kSaveLayerWithBoundsSize == opSize);
126 return kSaveLayerWithBoundsPaintOffset + overflow;
127 }
128 }
129
130 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method
131 return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
132}
mtklein8e126562014-10-01 09:29:35 -0700133#endif//SK_DEBUG
robertphillips@google.come37ad352013-03-01 19:44:30 +0000134
Florin Malita5f6102d2014-06-30 10:13:28 -0400135void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +0000136 // record the offset to us, making it non-positive to distinguish a save
137 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000138 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -0400139 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000140
Florin Malita5f6102d2014-06-30 10:13:28 -0400141 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000142}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000143
Florin Malita5f6102d2014-06-30 10:13:28 -0400144void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -0700145 fContentInfo.onSave();
146
Florin Malita5f6102d2014-06-30 10:13:28 -0400147 // op only
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000148 size_t size = kSaveSize;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000149 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +0000150
robertphillips@google.com8b169312013-10-15 17:47:36 +0000151 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152}
153
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000154SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
155 const SkPaint* paint, SaveFlags flags) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000156 // record the offset to us, making it non-positive to distinguish a save
157 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +0000158 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000159 this->recordSaveLayer(bounds, paint, flags);
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000160
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000161 this->INHERITED::willSaveLayer(bounds, paint, flags);
162 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000163 at this time (and may not be able to afford since during record our
164 clip starts out the size of the picture, which is often much larger
165 than the size of the actual device we'll use during playback).
166 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000167 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000168}
169
170void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000171 SaveFlags flags) {
robertphillipsc019ec42014-08-12 05:35:58 -0700172 fContentInfo.onSaveLayer();
173
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000174 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000175 size_t size = 2 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700176 if (bounds) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000177 size += sizeof(*bounds); // + rect
178 }
179 // + paint index + flags
180 size += 2 * kUInt32Size;
181
robertphillips@google.come37ad352013-03-01 19:44:30 +0000182 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
183
robertphillips@google.com8b169312013-10-15 17:47:36 +0000184 size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000185 this->addRectPtr(bounds);
mtklein8e126562014-10-01 09:29:35 -0700186 SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000187 this->addPaintPtr(paint);
188 this->addInt(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189
robertphillips@google.com8b169312013-10-15 17:47:36 +0000190 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191}
192
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000193#ifdef SK_DEBUG
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000194/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000195 * Read the op code from 'offset' in 'writer' and extract the size too.
196 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000197static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000198 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000199
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000200 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000201 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000202 if (MASK_24 == *size) {
203 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000204 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000205 }
206 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000207}
mtklein46616af2014-09-30 14:47:10 -0700208#endif//SK_DEBUG
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000209
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000210void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000211#if 0
212 SkASSERT(fRestoreOffsetStack.count() > 1);
213#endif
214
reed@android.comb4e22d62009-07-09 15:20:25 +0000215 // check for underflow
216 if (fRestoreOffsetStack.count() == 0) {
217 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000219
mtklein46616af2014-09-30 14:47:10 -0700220 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000221
reed@android.comb4e22d62009-07-09 15:20:25 +0000222 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000223
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000224 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000225}
226
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000227void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700228 fContentInfo.onRestore();
229
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000230 if (fillInSkips) {
231 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
232 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000233 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
234 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000235 this->validate(initialOffset, size);
236}
237
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000238void SkPictureRecord::recordTranslate(const SkMatrix& m) {
239 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
240
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000241 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000242 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000243 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000244 this->addScalar(m.getTranslateX());
245 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000246 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247}
248
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000249void SkPictureRecord::recordScale(const SkMatrix& m) {
250 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000251
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000252 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000253 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000254 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000255 this->addScalar(m.getScaleX());
256 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000257 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000258}
259
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000260void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000261 switch (matrix.getType()) {
262 case SkMatrix::kTranslate_Mask:
263 this->recordTranslate(matrix);
264 break;
265 case SkMatrix::kScale_Mask:
266 this->recordScale(matrix);
267 break;
268 default:
269 this->recordConcat(matrix);
270 break;
271 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000272 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000273}
274
275void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000276 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000277 // op + matrix
halcanary96fcdcc2015-08-27 07:41:13 -0700278 size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000279 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000280 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000281 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000282}
283
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000284void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000285 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000286 // op + matrix
halcanary96fcdcc2015-08-27 07:41:13 -0700287 size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000288 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000289 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000290 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000291 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000292}
293
reed@google.com45482d12011-08-29 19:02:39 +0000294static bool regionOpExpands(SkRegion::Op op) {
295 switch (op) {
296 case SkRegion::kUnion_Op:
297 case SkRegion::kXOR_Op:
298 case SkRegion::kReverseDifference_Op:
299 case SkRegion::kReplace_Op:
300 return true;
301 case SkRegion::kIntersect_Op:
302 case SkRegion::kDifference_Op:
303 return false;
304 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000305 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000306 return false;
307 }
308}
309
robertphillips@google.come37ad352013-03-01 19:44:30 +0000310void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000311 int32_t offset = fRestoreOffsetStack.top();
312 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000313 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
314 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000315 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000316 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000317
reed@google.comffacd3c2012-08-30 15:31:23 +0000318#ifdef SK_DEBUG
reed2ff1fce2014-12-11 07:07:37 -0800319 // offset of 0 has been disabled, so we skip it
320 if (offset > 0) {
321 // assert that the final offset value points to a save verb
322 uint32_t opSize;
323 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
324 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
325 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000326#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000327}
328
reed@google.comd86e7ab2012-09-27 20:31:31 +0000329void SkPictureRecord::beginRecording() {
330 // we have to call this *after* our constructor, to ensure that it gets
331 // recorded. This is balanced by restoreToCount() call from endRecording,
332 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000333 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000334}
335
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000336void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000337 SkASSERT(kNoInitialSave != fInitialSaveCount);
338 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000339}
340
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000341size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000342 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000343 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000344 }
345
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000346 // The RestoreOffset field is initially filled with a placeholder
347 // value that points to the offset of the previous RestoreOffset
348 // in the current stack level, thus forming a linked list so that
349 // the restore offsets can be filled in when the corresponding
350 // restore command is recorded.
351 int32_t prevOffset = fRestoreOffsetStack.top();
352
reed@google.com45482d12011-08-29 19:02:39 +0000353 if (regionOpExpands(op)) {
354 // Run back through any previous clip ops, and mark their offset to
355 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
356 // they could hide this clips ability to expand the clip (i.e. go from
357 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000358 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000359
360 // Reset the pointer back to the previous clip so that subsequent
361 // restores don't overwrite the offsets we just cleared.
362 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000363 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000364
reed@google.com44699382013-10-31 17:28:30 +0000365 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000366 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000367 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000368 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000369}
370
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000371void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000372 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000373 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000374}
375
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000376size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000377 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000378 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000379 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000380 if (!fRestoreOffsetStack.isEmpty()) {
381 // + restore offset
382 size += kUInt32Size;
383 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000384 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000385 this->addRect(rect);
386 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000387 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000388
robertphillips@google.com8b169312013-10-15 17:47:36 +0000389 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000390 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000391}
392
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000393void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000394 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700395 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000396}
397
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000398size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000399 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000400 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000401 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000402 if (!fRestoreOffsetStack.isEmpty()) {
403 // + restore offset
404 size += kUInt32Size;
405 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000406 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000407 this->addRRect(rrect);
408 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000409 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000410 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000411 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000412}
413
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000414void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000415 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000416 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700417 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000418}
419
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000420size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000421 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000422 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000423 // recordRestoreOffsetPlaceholder doesn't always write an offset
424 if (!fRestoreOffsetStack.isEmpty()) {
425 // + restore offset
426 size += kUInt32Size;
427 }
428 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000429 this->addInt(pathID);
430 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000431 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000432 this->validate(initialOffset, size);
433 return offset;
434}
435
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000436void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000437 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000438 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000439}
440
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000441size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000442 // op + clip params + region
halcanary96fcdcc2015-08-27 07:41:13 -0700443 size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000444 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000445 if (!fRestoreOffsetStack.isEmpty()) {
446 // + restore offset
447 size += kUInt32Size;
448 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000449 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000450 this->addRegion(region);
451 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000452 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000453
robertphillips@google.com8b169312013-10-15 17:47:36 +0000454 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000455 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456}
457
reed41af9662015-01-05 07:49:08 -0800458void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000459 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000460 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000461 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
mtklein8e126562014-10-01 09:29:35 -0700462 SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000463 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000464 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465}
466
reed41af9662015-01-05 07:49:08 -0800467void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
468 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700469 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000470
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000471 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000472 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000473 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
mtklein8e126562014-10-01 09:29:35 -0700474 SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000475 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700476
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000477 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000478 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000479 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000480 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000481}
482
reed41af9662015-01-05 07:49:08 -0800483void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000484 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000485 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000486 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
mtklein8e126562014-10-01 09:29:35 -0700487 SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000488 this->addPaint(paint);
489 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000490 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000491}
492
reed41af9662015-01-05 07:49:08 -0800493void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000494 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000495 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000496 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700497 SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000498 this->addPaint(paint);
499 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000500 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000501}
502
reed41af9662015-01-05 07:49:08 -0800503void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
mtklein46616af2014-09-30 14:47:10 -0700504 // op + paint index + rrect
505 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
506 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700507 SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700508 this->addPaint(paint);
509 this->addRRect(rrect);
510 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000511}
512
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000513void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
514 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000515 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000516 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
517 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
mtklein8e126562014-10-01 09:29:35 -0700518 SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten());
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000519 this->addPaint(paint);
520 this->addRRect(outer);
521 this->addRRect(inner);
522 this->validate(initialOffset, size);
523}
524
reed41af9662015-01-05 07:49:08 -0800525void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700526 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000527
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000528 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000529 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000530 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
mtklein8e126562014-10-01 09:29:35 -0700531 SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000532 this->addPaint(paint);
533 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000534 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535}
536
reed41af9662015-01-05 07:49:08 -0800537void SkPictureRecord::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
538 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000539 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000540 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000541 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
mtklein8e126562014-10-01 09:29:35 -0700542 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000543 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000544 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000545 this->addScalar(left);
546 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000547 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000548}
549
reed41af9662015-01-05 07:49:08 -0800550void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700551 const SkPaint* paint, SrcRectConstraint constraint) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000552 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000553 size_t size = 5 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700554 if (src) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000555 size += sizeof(*src); // + rect
556 }
557 size += sizeof(dst); // + rect
558
reeda5517e22015-07-14 10:54:12 -0700559 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT, &size);
560 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000561 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000562 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000563 this->addRectPtr(src); // may be null
564 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700565 this->addInt(constraint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000566 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000567}
568
reeda85d4d02015-05-06 12:56:48 -0700569void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
570 const SkPaint* paint) {
reed871872f2015-06-22 12:48:26 -0700571 // op + paint_index + image_index + x + y
572 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
573 size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
574 SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE, size) == fWriter.bytesWritten());
575 this->addPaintPtr(paint);
576 this->addImage(image);
577 this->addScalar(x);
578 this->addScalar(y);
579 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700580}
581
582void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700583 const SkPaint* paint, SrcRectConstraint constraint) {
reeda5517e22015-07-14 10:54:12 -0700584 // id + paint_index + image_index + bool_for_src + constraint
585 size_t size = 5 * kUInt32Size;
reed871872f2015-06-22 12:48:26 -0700586 if (src) {
587 size += sizeof(*src); // + rect
reeda85d4d02015-05-06 12:56:48 -0700588 }
reed871872f2015-06-22 12:48:26 -0700589 size += sizeof(dst); // + rect
mtkleinc2e29772015-10-30 05:24:58 -0700590
reed871872f2015-06-22 12:48:26 -0700591 size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
592 SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_RECT, size)
593 == fWriter.bytesWritten());
594 this->addPaintPtr(paint);
595 this->addImage(image);
596 this->addRectPtr(src); // may be null
597 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700598 this->addInt(constraint);
reed871872f2015-06-22 12:48:26 -0700599 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700600}
601
reed4c21dc52015-06-25 12:32:03 -0700602void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
603 const SkPaint* paint) {
604 // id + paint_index + image_index + center + dst
605 size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
mtkleinc2e29772015-10-30 05:24:58 -0700606
reed4c21dc52015-06-25 12:32:03 -0700607 size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
608 SkASSERT(initialOffset+get_paint_offset(DRAW_IMAGE_NINE, size) == fWriter.bytesWritten());
609 this->addPaintPtr(paint);
610 this->addImage(img);
611 this->addIRect(center);
612 this->addRect(dst);
613 this->validate(initialOffset, size);
614}
615
reed41af9662015-01-05 07:49:08 -0800616void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
617 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000618 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000619 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000620 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
mtklein8e126562014-10-01 09:29:35 -0700621 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000622 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000623 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000624 this->addIRect(center);
625 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000626 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000627}
628
reed41af9662015-01-05 07:49:08 -0800629void SkPictureRecord::onDrawSprite(const SkBitmap& bitmap, int left, int top,
630 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000631 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000632 size_t size = 5 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000633 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
mtklein8e126562014-10-01 09:29:35 -0700634 SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000635 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000636 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000637 this->addInt(left);
638 this->addInt(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000639 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000640}
641
reed@google.come0d9ce82014-04-23 04:00:17 +0000642void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
643 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000644 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000645 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000646
mtklein46616af2014-09-30 14:47:10 -0700647 DrawType op = DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000648 size_t initialOffset = this->addDraw(op, &size);
mtklein8e126562014-10-01 09:29:35 -0700649 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700650 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000651 this->addText(text, byteLength);
652 this->addScalar(x);
653 this->addScalar(y);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000654 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000655}
656
reed@google.come0d9ce82014-04-23 04:00:17 +0000657void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
658 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000659 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000660
mtklein46616af2014-09-30 14:47:10 -0700661 // op + paint index + length + 'length' worth of data + num points + x&y point data
662 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
reed@google.com82065d62011-02-07 15:30:46 +0000663
mtklein46616af2014-09-30 14:47:10 -0700664 DrawType op = DRAW_POS_TEXT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665
robertphillips@google.com8b169312013-10-15 17:47:36 +0000666 size_t initialOffset = this->addDraw(op, &size);
mtklein8e126562014-10-01 09:29:35 -0700667 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
mtklein46616af2014-09-30 14:47:10 -0700668 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000669 this->addText(text, byteLength);
670 this->addInt(points);
mtklein46616af2014-09-30 14:47:10 -0700671 fWriter.writeMul4(pos, points * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000672 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673}
674
reed@google.come0d9ce82014-04-23 04:00:17 +0000675void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
676 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000677 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000679 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000680 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000681 // + y + the actual points
682 size += 1 * kUInt32Size + points * sizeof(SkScalar);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000683
mtklein46616af2014-09-30 14:47:10 -0700684 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
685 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000686 this->addText(text, byteLength);
687 this->addInt(points);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000688 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000689 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000690 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000691}
692
reed@google.come0d9ce82014-04-23 04:00:17 +0000693void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
694 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000695 // op + paint index + length + 'length' worth of data + path index + matrix
696 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
halcanary96fcdcc2015-08-27 07:41:13 -0700697 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000698 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
mtklein8e126562014-10-01 09:29:35 -0700699 SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000700 this->addPaint(paint);
701 this->addText(text, byteLength);
702 this->addPath(path);
703 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000704 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000705}
706
fmalitab7425172014-08-26 07:56:44 -0700707void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
708 const SkPaint& paint) {
709
710 // op + paint index + blob index + x/y
711 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
712 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
mtklein8e126562014-10-01 09:29:35 -0700713 SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
fmalitab7425172014-08-26 07:56:44 -0700714
715 this->addPaint(paint);
716 this->addTextBlob(blob);
717 this->addScalar(x);
718 this->addScalar(y);
719
720 this->validate(initialOffset, size);
721}
722
reedd5fa1a42014-08-09 11:08:05 -0700723void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
724 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000725 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000726 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -0700727 size_t initialOffset;
728
halcanary96fcdcc2015-08-27 07:41:13 -0700729 if (nullptr == matrix && nullptr == paint) {
reedd5fa1a42014-08-09 11:08:05 -0700730 initialOffset = this->addDraw(DRAW_PICTURE, &size);
731 this->addPicture(picture);
732 } else {
733 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
halcanary96fcdcc2015-08-27 07:41:13 -0700734 size += m.writeToMemory(nullptr) + kUInt32Size; // matrix + paint
reedd5fa1a42014-08-09 11:08:05 -0700735 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
mtklein8e126562014-10-01 09:29:35 -0700736 SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size)
fmalita9f49cfd2014-08-12 12:24:17 -0700737 == fWriter.bytesWritten());
reedd5fa1a42014-08-09 11:08:05 -0700738 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -0700739 this->addMatrix(m);
740 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -0700741 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000742 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000743}
744
reed41af9662015-01-05 07:49:08 -0800745void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
746 const SkPoint vertices[], const SkPoint texs[],
747 const SkColor colors[], SkXfermode* xfer,
748 const uint16_t indices[], int indexCount,
749 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 uint32_t flags = 0;
751 if (texs) {
752 flags |= DRAW_VERTICES_HAS_TEXS;
753 }
754 if (colors) {
755 flags |= DRAW_VERTICES_HAS_COLORS;
756 }
757 if (indexCount > 0) {
758 flags |= DRAW_VERTICES_HAS_INDICES;
759 }
bsalomon49f085d2014-09-05 13:34:00 -0700760 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +0000761 SkXfermode::Mode mode;
762 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
763 flags |= DRAW_VERTICES_HAS_XFER;
764 }
765 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000766
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000767 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000768 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000769 if (flags & DRAW_VERTICES_HAS_TEXS) {
770 size += vertexCount * sizeof(SkPoint); // + uvs
771 }
772 if (flags & DRAW_VERTICES_HAS_COLORS) {
773 size += vertexCount * sizeof(SkColor); // + vert colors
774 }
775 if (flags & DRAW_VERTICES_HAS_INDICES) {
776 // + num indices + indices
777 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
778 }
reed@google.com85e143c2013-12-30 15:51:25 +0000779 if (flags & DRAW_VERTICES_HAS_XFER) {
780 size += kUInt32Size; // mode enum
781 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000782
robertphillips@google.com8b169312013-10-15 17:47:36 +0000783 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
mtklein8e126562014-10-01 09:29:35 -0700784 SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000785 this->addPaint(paint);
786 this->addInt(flags);
787 this->addInt(vmode);
788 this->addInt(vertexCount);
789 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000791 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792 }
793 if (flags & DRAW_VERTICES_HAS_COLORS) {
794 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
795 }
796 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000797 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000798 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
799 }
reed@google.com85e143c2013-12-30 15:51:25 +0000800 if (flags & DRAW_VERTICES_HAS_XFER) {
801 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
802 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000803 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +0000804 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000805 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000806}
807
dandovb3c9d1c2014-08-12 08:34:29 -0700808void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
809 const SkPoint texCoords[4], SkXfermode* xmode,
810 const SkPaint& paint) {
811 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
812 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
813 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -0700814 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700815 flag |= DRAW_VERTICES_HAS_COLORS;
816 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
817 }
bsalomon49f085d2014-09-05 13:34:00 -0700818 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700819 flag |= DRAW_VERTICES_HAS_TEXS;
820 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
821 }
bsalomon49f085d2014-09-05 13:34:00 -0700822 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -0700823 SkXfermode::Mode mode;
824 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
825 flag |= DRAW_VERTICES_HAS_XFER;
826 size += kUInt32Size;
827 }
828 }
mtklein46616af2014-09-30 14:47:10 -0700829
dandov963137b2014-08-07 07:49:53 -0700830 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
mtklein8e126562014-10-01 09:29:35 -0700831 SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten());
dandov963137b2014-08-07 07:49:53 -0700832 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -0700833 this->addPatch(cubics);
834 this->addInt(flag);
mtklein46616af2014-09-30 14:47:10 -0700835
dandovb3c9d1c2014-08-12 08:34:29 -0700836 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -0700837 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700838 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
839 }
bsalomon49f085d2014-09-05 13:34:00 -0700840 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700841 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
842 }
843 if (flag & DRAW_VERTICES_HAS_XFER) {
844 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
845 xmode->asMode(&mode);
846 this->addInt(mode);
847 }
dandov963137b2014-08-07 07:49:53 -0700848 this->validate(initialOffset, size);
849}
850
reed71c3c762015-06-24 10:29:17 -0700851void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
852 const SkColor colors[], int count, SkXfermode::Mode mode,
853 const SkRect* cull, const SkPaint* paint) {
854 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
855 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
856 uint32_t flags = 0;
857 if (colors) {
858 flags |= DRAW_ATLAS_HAS_COLORS;
859 size += count * sizeof(SkColor);
860 size += sizeof(uint32_t); // xfermode::mode
861 }
862 if (cull) {
863 flags |= DRAW_ATLAS_HAS_CULL;
864 size += sizeof(SkRect);
865 }
mtkleinc2e29772015-10-30 05:24:58 -0700866
reed71c3c762015-06-24 10:29:17 -0700867 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
868 SkASSERT(initialOffset+get_paint_offset(DRAW_ATLAS, size) == fWriter.bytesWritten());
869 this->addPaintPtr(paint);
870 this->addImage(atlas);
871 this->addInt(flags);
872 this->addInt(count);
873 fWriter.write(xform, count * sizeof(SkRSXform));
874 fWriter.write(tex, count * sizeof(SkRect));
875
876 // write optional parameters
877 if (colors) {
878 fWriter.write(colors, count * sizeof(SkColor));
879 this->addInt(mode);
880 }
881 if (cull) {
882 fWriter.write(cull, sizeof(SkRect));
883 }
884 this->validate(initialOffset, size);
885}
886
reed@android.com8a1c16f2008-12-17 15:59:43 +0000887///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000888
reed4a8126e2014-09-22 07:29:03 -0700889SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
halcanary96fcdcc2015-08-27 07:41:13 -0700890 return nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +0000891}
892
mtkleine0694002014-11-12 12:49:47 -0800893// If we already have a stored, can we reuse it instead of also storing b?
894static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
895 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
896 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
897 // but it sure makes things easier to reason about below.
898 return false;
899 }
900 if (a.pixelRef() == b.pixelRef()) {
901 return true; // Same shape and same pixels -> same bitmap.
902 }
903
904 // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
905 if (!a.pixelRef() || !b.pixelRef()) {
906 return false;
907 }
908
909 // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
910 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
911 encB(b.pixelRef()->refEncodedData());
912 if (encA && encB) {
913 return encA->equals(encB);
914 } else if (encA || encB) {
915 return false; // One has encoded data but the other does not.
916 }
917
918 // As a last resort, we have to look at the pixels. This will read back textures.
919 SkAutoLockPixels al(a), bl(b);
920 const char* ap = (const char*)a.getPixels();
921 const char* bp = (const char*)b.getPixels();
922 if (ap && bp) {
923 // We check row by row; row bytes might differ.
924 SkASSERT(a.info() == b.info()); // We checked this above.
925 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true.
926 const SkImageInfo info = a.info();
927 const size_t bytesToCompare = info.width() * info.bytesPerPixel();
928 for (int row = 0; row < info.height(); row++) {
929 if (0 != memcmp(ap, bp, bytesToCompare)) {
930 return false;
931 }
932 ap += a.rowBytes();
933 bp += b.rowBytes();
934 }
935 return true;
936 }
937 return false; // Couldn't get pixels for both bitmaps.
938}
939
940void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
941 // First see if we already have this bitmap. This deduplication should really
942 // only be important for our tests, where bitmaps tend not to be tagged immutable.
943 // In Chrome (and hopefully Android?) they're typically immutable.
944 for (int i = 0; i < fBitmaps.count(); i++) {
945 if (equivalent(fBitmaps[i], bitmap)) {
946 this->addInt(i); // Unlike the rest, bitmap indices are 0-based.
947 return;
948 }
949 }
950 // Don't have it. We'll add it to our list, making sure it's tagged as immutable.
mtklein71a23632014-11-12 10:24:55 -0800951 if (bitmap.isImmutable()) {
mtkleine0694002014-11-12 12:49:47 -0800952 // Shallow copies of bitmaps are cheap, so immutable == fast.
mtklein71a23632014-11-12 10:24:55 -0800953 fBitmaps.push_back(bitmap);
954 } else {
mtkleine0694002014-11-12 12:49:47 -0800955 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
mtklein71a23632014-11-12 10:24:55 -0800956 SkBitmap copy;
957 bitmap.copyTo(&copy);
958 copy.setImmutable();
959 fBitmaps.push_back(copy);
960 }
mtkleine0694002014-11-12 12:49:47 -0800961 this->addInt(fBitmaps.count()-1); // Remember, 0-based.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000962}
963
reed871872f2015-06-22 12:48:26 -0700964void SkPictureRecord::addImage(const SkImage* image) {
965 int index = fImageRefs.find(image);
966 if (index >= 0) {
967 this->addInt(index);
968 } else {
969 *fImageRefs.append() = SkRef(image);
970 this->addInt(fImageRefs.count()-1);
971 }
972}
973
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000975 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976}
977
mtklein46616af2014-09-30 14:47:10 -0700978void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -0700979 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000980
mtklein46616af2014-09-30 14:47:10 -0700981 if (paint) {
mtkleina74ce852014-11-12 09:19:02 -0800982 fPaints.push_back(*paint);
983 this->addInt(fPaints.count());
mtklein46616af2014-09-30 14:47:10 -0700984 } else {
985 this->addInt(0);
986 }
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000987}
988
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000989int SkPictureRecord::addPathToHeap(const SkPath& path) {
mtkleinc2e29772015-10-30 05:24:58 -0700990 if (int* n = fPaths.find(path)) {
991 return *n;
992 }
993 int n = fPaths.count() + 1; // 0 is reserved for null / error.
994 fPaths.set(path, n);
995 return n;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000996}
997
998void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000999 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001000}
1001
dandovb3c9d1c2014-08-12 08:34:29 -07001002void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
1003 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -07001004}
1005
robertphillips9b14f262014-06-04 05:40:44 -07001006void SkPictureRecord::addPicture(const SkPicture* picture) {
1007 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001008 if (index < 0) { // not found
1009 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -07001010 *fPictureRefs.append() = picture;
1011 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001012 }
1013 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +00001014 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001015}
1016
1017void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001018 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001019}
reed@google.com82065d62011-02-07 15:30:46 +00001020
reed@android.com8a1c16f2008-12-17 15:59:43 +00001021void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1022 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001023}
1024
senorblanco@chromium.org68250c82014-05-06 22:52:55 +00001025void SkPictureRecord::addNoOp() {
1026 size_t size = kUInt32Size; // op
1027 this->addDraw(NOOP, &size);
1028}
1029
reed@android.com8a1c16f2008-12-17 15:59:43 +00001030void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001032}
1033
1034void SkPictureRecord::addRectPtr(const SkRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001035 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001036 fWriter.writeRect(*rect);
1037 }
1038}
1039
reed@google.comf0b5e112011-09-07 11:57:34 +00001040void SkPictureRecord::addIRect(const SkIRect& rect) {
1041 fWriter.write(&rect, sizeof(rect));
1042}
1043
reed@android.com8a1c16f2008-12-17 15:59:43 +00001044void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -07001045 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001046 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1047 }
1048}
1049
reed@google.com4ed0fb72012-12-12 20:48:18 +00001050void SkPictureRecord::addRRect(const SkRRect& rrect) {
1051 fWriter.writeRRect(rrect);
1052}
1053
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +00001055 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001056}
1057
1058void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -07001059 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +00001060 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +00001061 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062}
1063
fmalitab7425172014-08-26 07:56:44 -07001064void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -07001065 int index = fTextBlobRefs.count();
1066 *fTextBlobRefs.append() = blob;
1067 blob->ref();
fmalitab7425172014-08-26 07:56:44 -07001068 // follow the convention of recording a 1-based index
1069 this->addInt(index + 1);
1070}
1071
reed@android.com8a1c16f2008-12-17 15:59:43 +00001072///////////////////////////////////////////////////////////////////////////////
1073