blob: 7907ee0d2935f22b30ceca2be899d0b1b5a506e6 [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
robertphillips0bdbea72014-06-11 11:37:55 -070028SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000029 : INHERITED(dimensions.width(), dimensions.height())
mtklein71a23632014-11-12 10:24:55 -080030 , fRecordFlags(flags)
31 , fInitialSaveCount(kNoInitialSave) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000032}
33
34SkPictureRecord::~SkPictureRecord() {
robertphillips5351aad2015-06-23 06:54:56 -070035 fImageRefs.unrefAll();
djsollen@google.com21830d92012-08-07 19:49:41 +000036 fPictureRefs.unrefAll();
fmalitab7425172014-08-26 07:56:44 -070037 fTextBlobRefs.unrefAll();
reed@android.com8a1c16f2008-12-17 15:59:43 +000038}
39
40///////////////////////////////////////////////////////////////////////////////
41
Florin Malita5f6102d2014-06-30 10:13:28 -040042void SkPictureRecord::willSave() {
reed@google.comffacd3c2012-08-30 15:31:23 +000043 // record the offset to us, making it non-positive to distinguish a save
44 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +000045 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
Florin Malita5f6102d2014-06-30 10:13:28 -040046 this->recordSave();
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +000047
Florin Malita5f6102d2014-06-30 10:13:28 -040048 this->INHERITED::willSave();
robertphillips@google.com5a63f242014-02-04 20:07:50 +000049}
skia.committer@gmail.com11f86922012-08-31 17:14:46 +000050
Florin Malita5f6102d2014-06-30 10:13:28 -040051void SkPictureRecord::recordSave() {
robertphillipsc019ec42014-08-12 05:35:58 -070052 fContentInfo.onSave();
53
Florin Malita5f6102d2014-06-30 10:13:28 -040054 // op only
reed512f3e32016-01-04 14:11:31 -080055 size_t size = sizeof(kUInt32Size);
robertphillips@google.com8b169312013-10-15 17:47:36 +000056 size_t initialOffset = this->addDraw(SAVE, &size);
reed@google.com82065d62011-02-07 15:30:46 +000057
robertphillips@google.com8b169312013-10-15 17:47:36 +000058 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +000059}
60
reed4960eee2015-12-18 07:09:18 -080061SkCanvas::SaveLayerStrategy SkPictureRecord::getSaveLayerStrategy(const SaveLayerRec& rec) {
reed@google.comffacd3c2012-08-30 15:31:23 +000062 // record the offset to us, making it non-positive to distinguish a save
63 // from a clip entry.
reed@google.com44699382013-10-31 17:28:30 +000064 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
reed4960eee2015-12-18 07:09:18 -080065 this->recordSaveLayer(rec);
skia.committer@gmail.com11f86922012-08-31 17:14:46 +000066
reed4960eee2015-12-18 07:09:18 -080067 (void)this->INHERITED::getSaveLayerStrategy(rec);
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +000068 /* No need for a (potentially very big) layer which we don't actually need
robertphillips@google.com5a63f242014-02-04 20:07:50 +000069 at this time (and may not be able to afford since during record our
70 clip starts out the size of the picture, which is often much larger
71 than the size of the actual device we'll use during playback).
72 */
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +000073 return kNoLayer_SaveLayerStrategy;
robertphillips@google.com5a63f242014-02-04 20:07:50 +000074}
75
reed4960eee2015-12-18 07:09:18 -080076void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) {
robertphillipsc019ec42014-08-12 05:35:58 -070077 fContentInfo.onSaveLayer();
78
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000079 // op + bool for 'bounds'
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000080 size_t size = 2 * kUInt32Size;
reed4960eee2015-12-18 07:09:18 -080081 if (rec.fBounds) {
82 size += sizeof(*rec.fBounds); // + rect
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000083 }
84 // + paint index + flags
85 size += 2 * kUInt32Size;
86
reed4960eee2015-12-18 07:09:18 -080087 size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERFLAGS, &size);
88 this->addRectPtr(rec.fBounds);
reed4960eee2015-12-18 07:09:18 -080089 this->addPaintPtr(rec.fPaint);
90 this->addInt(rec.fSaveLayerFlags);
reed@android.com8a1c16f2008-12-17 15:59:43 +000091
robertphillips@google.com8b169312013-10-15 17:47:36 +000092 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +000093}
94
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +000095#ifdef SK_DEBUG
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +000096/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000097 * Read the op code from 'offset' in 'writer' and extract the size too.
98 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000099static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000100 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000101
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000102 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000103 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000104 if (MASK_24 == *size) {
105 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000106 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000107 }
108 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000109}
mtklein46616af2014-09-30 14:47:10 -0700110#endif//SK_DEBUG
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000111
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000112void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000113#if 0
114 SkASSERT(fRestoreOffsetStack.count() > 1);
115#endif
116
reed@android.comb4e22d62009-07-09 15:20:25 +0000117 // check for underflow
118 if (fRestoreOffsetStack.count() == 0) {
119 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000121
mtklein46616af2014-09-30 14:47:10 -0700122 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000123
reed@android.comb4e22d62009-07-09 15:20:25 +0000124 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000125
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000126 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127}
128
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000129void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700130 fContentInfo.onRestore();
131
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000132 if (fillInSkips) {
133 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
134 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000135 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
136 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000137 this->validate(initialOffset, size);
138}
139
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000140void SkPictureRecord::recordTranslate(const SkMatrix& m) {
141 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
142
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000143 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000144 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000145 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000146 this->addScalar(m.getTranslateX());
147 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000148 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149}
150
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000151void SkPictureRecord::recordScale(const SkMatrix& m) {
152 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000153
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000154 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000155 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000156 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000157 this->addScalar(m.getScaleX());
158 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000159 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160}
161
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000162void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000163 switch (matrix.getType()) {
164 case SkMatrix::kTranslate_Mask:
165 this->recordTranslate(matrix);
166 break;
167 case SkMatrix::kScale_Mask:
168 this->recordScale(matrix);
169 break;
170 default:
171 this->recordConcat(matrix);
172 break;
173 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000174 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000175}
176
177void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000178 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000179 // op + matrix
halcanary96fcdcc2015-08-27 07:41:13 -0700180 size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000181 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000182 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000183 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184}
185
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000186void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000187 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000188 // op + matrix
halcanary96fcdcc2015-08-27 07:41:13 -0700189 size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000190 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000191 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000192 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000193 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000194}
195
reed@google.com45482d12011-08-29 19:02:39 +0000196static bool regionOpExpands(SkRegion::Op op) {
197 switch (op) {
198 case SkRegion::kUnion_Op:
199 case SkRegion::kXOR_Op:
200 case SkRegion::kReverseDifference_Op:
201 case SkRegion::kReplace_Op:
202 return true;
203 case SkRegion::kIntersect_Op:
204 case SkRegion::kDifference_Op:
205 return false;
206 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000207 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000208 return false;
209 }
210}
211
robertphillips@google.come37ad352013-03-01 19:44:30 +0000212void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000213 int32_t offset = fRestoreOffsetStack.top();
214 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000215 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
216 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000217 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000218 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000219
reed@google.comffacd3c2012-08-30 15:31:23 +0000220#ifdef SK_DEBUG
reed2ff1fce2014-12-11 07:07:37 -0800221 // offset of 0 has been disabled, so we skip it
222 if (offset > 0) {
223 // assert that the final offset value points to a save verb
224 uint32_t opSize;
225 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed4960eee2015-12-18 07:09:18 -0800226 SkASSERT(SAVE_LAYER_SAVEFLAGS_DEPRECATED != drawOp);
227 SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERFLAGS == drawOp);
reed2ff1fce2014-12-11 07:07:37 -0800228 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000229#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000230}
231
reed@google.comd86e7ab2012-09-27 20:31:31 +0000232void SkPictureRecord::beginRecording() {
233 // we have to call this *after* our constructor, to ensure that it gets
234 // recorded. This is balanced by restoreToCount() call from endRecording,
235 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000236 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000237}
238
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000239void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000240 SkASSERT(kNoInitialSave != fInitialSaveCount);
241 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000242}
243
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000244size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000245 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000246 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000247 }
248
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000249 // The RestoreOffset field is initially filled with a placeholder
250 // value that points to the offset of the previous RestoreOffset
251 // in the current stack level, thus forming a linked list so that
252 // the restore offsets can be filled in when the corresponding
253 // restore command is recorded.
254 int32_t prevOffset = fRestoreOffsetStack.top();
255
reed@google.com45482d12011-08-29 19:02:39 +0000256 if (regionOpExpands(op)) {
257 // Run back through any previous clip ops, and mark their offset to
258 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
259 // they could hide this clips ability to expand the clip (i.e. go from
260 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000261 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000262
263 // Reset the pointer back to the previous clip so that subsequent
264 // restores don't overwrite the offsets we just cleared.
265 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000266 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000267
reed@google.com44699382013-10-31 17:28:30 +0000268 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000269 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000270 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000271 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000272}
273
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000274void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000275 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000276 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000277}
278
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000279size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000280 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000281 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000282 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000283 if (!fRestoreOffsetStack.isEmpty()) {
284 // + restore offset
285 size += kUInt32Size;
286 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000287 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000288 this->addRect(rect);
289 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000290 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000291
robertphillips@google.com8b169312013-10-15 17:47:36 +0000292 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000293 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294}
295
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000296void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000297 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700298 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000299}
300
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000301size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000302 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000303 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000304 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000305 if (!fRestoreOffsetStack.isEmpty()) {
306 // + restore offset
307 size += kUInt32Size;
308 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000309 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000310 this->addRRect(rrect);
311 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000312 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000313 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000314 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000315}
316
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000317void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000318 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000319 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700320 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000321}
322
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000323size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000324 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000325 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000326 // recordRestoreOffsetPlaceholder doesn't always write an offset
327 if (!fRestoreOffsetStack.isEmpty()) {
328 // + restore offset
329 size += kUInt32Size;
330 }
331 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000332 this->addInt(pathID);
333 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000334 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000335 this->validate(initialOffset, size);
336 return offset;
337}
338
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000339void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000340 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000341 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000342}
343
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000344size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000345 // op + clip params + region
halcanary96fcdcc2015-08-27 07:41:13 -0700346 size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000347 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000348 if (!fRestoreOffsetStack.isEmpty()) {
349 // + restore offset
350 size += kUInt32Size;
351 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000352 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000353 this->addRegion(region);
354 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000355 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000356
robertphillips@google.com8b169312013-10-15 17:47:36 +0000357 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000358 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000359}
360
reed41af9662015-01-05 07:49:08 -0800361void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000362 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000363 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000364 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000365 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000366 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000367}
368
reed41af9662015-01-05 07:49:08 -0800369void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
370 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700371 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000372
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000373 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000374 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000375 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000376 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700377
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000378 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000379 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000380 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000381 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382}
383
reed41af9662015-01-05 07:49:08 -0800384void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000385 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000386 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000387 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000388 this->addPaint(paint);
389 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000390 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000391}
392
reed41af9662015-01-05 07:49:08 -0800393void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000394 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000395 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000396 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000397 this->addPaint(paint);
398 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000399 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400}
401
reed41af9662015-01-05 07:49:08 -0800402void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
mtklein46616af2014-09-30 14:47:10 -0700403 // op + paint index + rrect
404 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
405 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
mtklein46616af2014-09-30 14:47:10 -0700406 this->addPaint(paint);
407 this->addRRect(rrect);
408 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000409}
410
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000411void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
412 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000413 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000414 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
415 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000416 this->addPaint(paint);
417 this->addRRect(outer);
418 this->addRRect(inner);
419 this->validate(initialOffset, size);
420}
421
reed41af9662015-01-05 07:49:08 -0800422void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700423 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000424
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000425 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000426 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000427 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000428 this->addPaint(paint);
429 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000430 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000431}
432
reed41af9662015-01-05 07:49:08 -0800433void SkPictureRecord::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
434 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000435 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000436 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000437 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000438 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000439 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000440 this->addScalar(left);
441 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000442 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000443}
444
reed41af9662015-01-05 07:49:08 -0800445void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700446 const SkPaint* paint, SrcRectConstraint constraint) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000447 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000448 size_t size = 5 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700449 if (src) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000450 size += sizeof(*src); // + rect
451 }
452 size += sizeof(dst); // + rect
453
reeda5517e22015-07-14 10:54:12 -0700454 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000455 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000456 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000457 this->addRectPtr(src); // may be null
458 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700459 this->addInt(constraint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000460 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000461}
462
reeda85d4d02015-05-06 12:56:48 -0700463void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
464 const SkPaint* paint) {
reed871872f2015-06-22 12:48:26 -0700465 // op + paint_index + image_index + x + y
466 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
467 size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
reed871872f2015-06-22 12:48:26 -0700468 this->addPaintPtr(paint);
469 this->addImage(image);
470 this->addScalar(x);
471 this->addScalar(y);
472 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700473}
474
475void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700476 const SkPaint* paint, SrcRectConstraint constraint) {
reeda5517e22015-07-14 10:54:12 -0700477 // id + paint_index + image_index + bool_for_src + constraint
478 size_t size = 5 * kUInt32Size;
reed871872f2015-06-22 12:48:26 -0700479 if (src) {
480 size += sizeof(*src); // + rect
reeda85d4d02015-05-06 12:56:48 -0700481 }
reed871872f2015-06-22 12:48:26 -0700482 size += sizeof(dst); // + rect
mtkleinc2e29772015-10-30 05:24:58 -0700483
reed871872f2015-06-22 12:48:26 -0700484 size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
reed871872f2015-06-22 12:48:26 -0700485 this->addPaintPtr(paint);
486 this->addImage(image);
487 this->addRectPtr(src); // may be null
488 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700489 this->addInt(constraint);
reed871872f2015-06-22 12:48:26 -0700490 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700491}
492
reed4c21dc52015-06-25 12:32:03 -0700493void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
494 const SkPaint* paint) {
495 // id + paint_index + image_index + center + dst
496 size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
mtkleinc2e29772015-10-30 05:24:58 -0700497
reed4c21dc52015-06-25 12:32:03 -0700498 size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
reed4c21dc52015-06-25 12:32:03 -0700499 this->addPaintPtr(paint);
500 this->addImage(img);
501 this->addIRect(center);
502 this->addRect(dst);
503 this->validate(initialOffset, size);
504}
505
reed41af9662015-01-05 07:49:08 -0800506void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
507 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000508 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000509 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000510 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000511 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000512 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000513 this->addIRect(center);
514 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000515 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000516}
517
reed@google.come0d9ce82014-04-23 04:00:17 +0000518void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
519 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000520 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000521 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000522
mtklein46616af2014-09-30 14:47:10 -0700523 DrawType op = DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000524 size_t initialOffset = this->addDraw(op, &size);
mtklein46616af2014-09-30 14:47:10 -0700525 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000526 this->addText(text, byteLength);
527 this->addScalar(x);
528 this->addScalar(y);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000529 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000530}
531
reed@google.come0d9ce82014-04-23 04:00:17 +0000532void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
533 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000534 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535
mtklein46616af2014-09-30 14:47:10 -0700536 // op + paint index + length + 'length' worth of data + num points + x&y point data
537 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
reed@google.com82065d62011-02-07 15:30:46 +0000538
mtklein46616af2014-09-30 14:47:10 -0700539 DrawType op = DRAW_POS_TEXT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000540
robertphillips@google.com8b169312013-10-15 17:47:36 +0000541 size_t initialOffset = this->addDraw(op, &size);
mtklein46616af2014-09-30 14:47:10 -0700542 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000543 this->addText(text, byteLength);
544 this->addInt(points);
mtklein46616af2014-09-30 14:47:10 -0700545 fWriter.writeMul4(pos, points * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000546 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000547}
548
reed@google.come0d9ce82014-04-23 04:00:17 +0000549void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
550 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000551 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000553 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000554 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000555 // + y + the actual points
556 size += 1 * kUInt32Size + points * sizeof(SkScalar);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000557
mtklein46616af2014-09-30 14:47:10 -0700558 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
559 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000560 this->addText(text, byteLength);
561 this->addInt(points);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000562 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000563 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000564 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565}
566
reed@google.come0d9ce82014-04-23 04:00:17 +0000567void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
568 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000569 // op + paint index + length + 'length' worth of data + path index + matrix
570 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
halcanary96fcdcc2015-08-27 07:41:13 -0700571 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000572 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000573 this->addPaint(paint);
574 this->addText(text, byteLength);
575 this->addPath(path);
576 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000577 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578}
579
fmalitab7425172014-08-26 07:56:44 -0700580void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
581 const SkPaint& paint) {
582
583 // op + paint index + blob index + x/y
584 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
585 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
fmalitab7425172014-08-26 07:56:44 -0700586
587 this->addPaint(paint);
588 this->addTextBlob(blob);
589 this->addScalar(x);
590 this->addScalar(y);
591
592 this->validate(initialOffset, size);
593}
594
reedd5fa1a42014-08-09 11:08:05 -0700595void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
596 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000597 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000598 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -0700599 size_t initialOffset;
600
halcanary96fcdcc2015-08-27 07:41:13 -0700601 if (nullptr == matrix && nullptr == paint) {
reedd5fa1a42014-08-09 11:08:05 -0700602 initialOffset = this->addDraw(DRAW_PICTURE, &size);
603 this->addPicture(picture);
604 } else {
605 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
halcanary96fcdcc2015-08-27 07:41:13 -0700606 size += m.writeToMemory(nullptr) + kUInt32Size; // matrix + paint
reedd5fa1a42014-08-09 11:08:05 -0700607 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
reedd5fa1a42014-08-09 11:08:05 -0700608 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -0700609 this->addMatrix(m);
610 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -0700611 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000612 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000613}
614
reed41af9662015-01-05 07:49:08 -0800615void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
616 const SkPoint vertices[], const SkPoint texs[],
617 const SkColor colors[], SkXfermode* xfer,
618 const uint16_t indices[], int indexCount,
619 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000620 uint32_t flags = 0;
621 if (texs) {
622 flags |= DRAW_VERTICES_HAS_TEXS;
623 }
624 if (colors) {
625 flags |= DRAW_VERTICES_HAS_COLORS;
626 }
627 if (indexCount > 0) {
628 flags |= DRAW_VERTICES_HAS_INDICES;
629 }
bsalomon49f085d2014-09-05 13:34:00 -0700630 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +0000631 SkXfermode::Mode mode;
632 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
633 flags |= DRAW_VERTICES_HAS_XFER;
634 }
635 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000637 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000638 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000639 if (flags & DRAW_VERTICES_HAS_TEXS) {
640 size += vertexCount * sizeof(SkPoint); // + uvs
641 }
642 if (flags & DRAW_VERTICES_HAS_COLORS) {
643 size += vertexCount * sizeof(SkColor); // + vert colors
644 }
645 if (flags & DRAW_VERTICES_HAS_INDICES) {
646 // + num indices + indices
647 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
648 }
reed@google.com85e143c2013-12-30 15:51:25 +0000649 if (flags & DRAW_VERTICES_HAS_XFER) {
650 size += kUInt32Size; // mode enum
651 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000652
robertphillips@google.com8b169312013-10-15 17:47:36 +0000653 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000654 this->addPaint(paint);
655 this->addInt(flags);
656 this->addInt(vmode);
657 this->addInt(vertexCount);
658 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000659 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000660 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661 }
662 if (flags & DRAW_VERTICES_HAS_COLORS) {
663 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
664 }
665 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000666 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
668 }
reed@google.com85e143c2013-12-30 15:51:25 +0000669 if (flags & DRAW_VERTICES_HAS_XFER) {
670 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
671 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000672 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +0000673 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000674 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000675}
676
dandovb3c9d1c2014-08-12 08:34:29 -0700677void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
678 const SkPoint texCoords[4], SkXfermode* xmode,
679 const SkPaint& paint) {
680 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
681 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
682 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -0700683 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700684 flag |= DRAW_VERTICES_HAS_COLORS;
685 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
686 }
bsalomon49f085d2014-09-05 13:34:00 -0700687 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700688 flag |= DRAW_VERTICES_HAS_TEXS;
689 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
690 }
bsalomon49f085d2014-09-05 13:34:00 -0700691 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -0700692 SkXfermode::Mode mode;
693 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
694 flag |= DRAW_VERTICES_HAS_XFER;
695 size += kUInt32Size;
696 }
697 }
mtklein46616af2014-09-30 14:47:10 -0700698
dandov963137b2014-08-07 07:49:53 -0700699 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
dandov963137b2014-08-07 07:49:53 -0700700 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -0700701 this->addPatch(cubics);
702 this->addInt(flag);
mtklein46616af2014-09-30 14:47:10 -0700703
dandovb3c9d1c2014-08-12 08:34:29 -0700704 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -0700705 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700706 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
707 }
bsalomon49f085d2014-09-05 13:34:00 -0700708 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700709 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
710 }
711 if (flag & DRAW_VERTICES_HAS_XFER) {
712 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
713 xmode->asMode(&mode);
714 this->addInt(mode);
715 }
dandov963137b2014-08-07 07:49:53 -0700716 this->validate(initialOffset, size);
717}
718
reed71c3c762015-06-24 10:29:17 -0700719void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
720 const SkColor colors[], int count, SkXfermode::Mode mode,
721 const SkRect* cull, const SkPaint* paint) {
722 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
723 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
724 uint32_t flags = 0;
725 if (colors) {
726 flags |= DRAW_ATLAS_HAS_COLORS;
727 size += count * sizeof(SkColor);
728 size += sizeof(uint32_t); // xfermode::mode
729 }
730 if (cull) {
731 flags |= DRAW_ATLAS_HAS_CULL;
732 size += sizeof(SkRect);
733 }
mtkleinc2e29772015-10-30 05:24:58 -0700734
reed71c3c762015-06-24 10:29:17 -0700735 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
reed71c3c762015-06-24 10:29:17 -0700736 this->addPaintPtr(paint);
737 this->addImage(atlas);
738 this->addInt(flags);
739 this->addInt(count);
740 fWriter.write(xform, count * sizeof(SkRSXform));
741 fWriter.write(tex, count * sizeof(SkRect));
742
743 // write optional parameters
744 if (colors) {
745 fWriter.write(colors, count * sizeof(SkColor));
746 this->addInt(mode);
747 }
748 if (cull) {
749 fWriter.write(cull, sizeof(SkRect));
750 }
751 this->validate(initialOffset, size);
752}
753
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000755
reed4a8126e2014-09-22 07:29:03 -0700756SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
halcanary96fcdcc2015-08-27 07:41:13 -0700757 return nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +0000758}
759
mtkleine0694002014-11-12 12:49:47 -0800760// If we already have a stored, can we reuse it instead of also storing b?
761static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
762 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
763 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
764 // but it sure makes things easier to reason about below.
765 return false;
766 }
767 if (a.pixelRef() == b.pixelRef()) {
768 return true; // Same shape and same pixels -> same bitmap.
769 }
770
771 // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
772 if (!a.pixelRef() || !b.pixelRef()) {
773 return false;
774 }
775
776 // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
777 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
778 encB(b.pixelRef()->refEncodedData());
779 if (encA && encB) {
780 return encA->equals(encB);
781 } else if (encA || encB) {
782 return false; // One has encoded data but the other does not.
783 }
784
785 // As a last resort, we have to look at the pixels. This will read back textures.
786 SkAutoLockPixels al(a), bl(b);
787 const char* ap = (const char*)a.getPixels();
788 const char* bp = (const char*)b.getPixels();
789 if (ap && bp) {
790 // We check row by row; row bytes might differ.
791 SkASSERT(a.info() == b.info()); // We checked this above.
792 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true.
793 const SkImageInfo info = a.info();
794 const size_t bytesToCompare = info.width() * info.bytesPerPixel();
795 for (int row = 0; row < info.height(); row++) {
796 if (0 != memcmp(ap, bp, bytesToCompare)) {
797 return false;
798 }
799 ap += a.rowBytes();
800 bp += b.rowBytes();
801 }
802 return true;
803 }
804 return false; // Couldn't get pixels for both bitmaps.
805}
806
807void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
808 // First see if we already have this bitmap. This deduplication should really
809 // only be important for our tests, where bitmaps tend not to be tagged immutable.
810 // In Chrome (and hopefully Android?) they're typically immutable.
811 for (int i = 0; i < fBitmaps.count(); i++) {
812 if (equivalent(fBitmaps[i], bitmap)) {
813 this->addInt(i); // Unlike the rest, bitmap indices are 0-based.
814 return;
815 }
816 }
817 // Don't have it. We'll add it to our list, making sure it's tagged as immutable.
mtklein71a23632014-11-12 10:24:55 -0800818 if (bitmap.isImmutable()) {
mtkleine0694002014-11-12 12:49:47 -0800819 // Shallow copies of bitmaps are cheap, so immutable == fast.
mtklein71a23632014-11-12 10:24:55 -0800820 fBitmaps.push_back(bitmap);
821 } else {
mtkleine0694002014-11-12 12:49:47 -0800822 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
mtklein71a23632014-11-12 10:24:55 -0800823 SkBitmap copy;
824 bitmap.copyTo(&copy);
825 copy.setImmutable();
826 fBitmaps.push_back(copy);
827 }
mtkleine0694002014-11-12 12:49:47 -0800828 this->addInt(fBitmaps.count()-1); // Remember, 0-based.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000829}
830
reed871872f2015-06-22 12:48:26 -0700831void SkPictureRecord::addImage(const SkImage* image) {
832 int index = fImageRefs.find(image);
833 if (index >= 0) {
834 this->addInt(index);
835 } else {
836 *fImageRefs.append() = SkRef(image);
837 this->addInt(fImageRefs.count()-1);
838 }
839}
840
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000842 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000843}
844
mtklein46616af2014-09-30 14:47:10 -0700845void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -0700846 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000847
mtklein46616af2014-09-30 14:47:10 -0700848 if (paint) {
mtkleina74ce852014-11-12 09:19:02 -0800849 fPaints.push_back(*paint);
850 this->addInt(fPaints.count());
mtklein46616af2014-09-30 14:47:10 -0700851 } else {
852 this->addInt(0);
853 }
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000854}
855
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000856int SkPictureRecord::addPathToHeap(const SkPath& path) {
mtkleinc2e29772015-10-30 05:24:58 -0700857 if (int* n = fPaths.find(path)) {
858 return *n;
859 }
860 int n = fPaths.count() + 1; // 0 is reserved for null / error.
861 fPaths.set(path, n);
862 return n;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000863}
864
865void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000866 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867}
868
dandovb3c9d1c2014-08-12 08:34:29 -0700869void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
870 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -0700871}
872
robertphillips9b14f262014-06-04 05:40:44 -0700873void SkPictureRecord::addPicture(const SkPicture* picture) {
874 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000875 if (index < 0) { // not found
876 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -0700877 *fPictureRefs.append() = picture;
878 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879 }
880 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000881 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000882}
883
884void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000885 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000886}
reed@google.com82065d62011-02-07 15:30:46 +0000887
reed@android.com8a1c16f2008-12-17 15:59:43 +0000888void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
889 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000890}
891
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000892void SkPictureRecord::addNoOp() {
893 size_t size = kUInt32Size; // op
894 this->addDraw(NOOP, &size);
895}
896
reed@android.com8a1c16f2008-12-17 15:59:43 +0000897void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000899}
900
901void SkPictureRecord::addRectPtr(const SkRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -0700902 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000903 fWriter.writeRect(*rect);
904 }
905}
906
reed@google.comf0b5e112011-09-07 11:57:34 +0000907void SkPictureRecord::addIRect(const SkIRect& rect) {
908 fWriter.write(&rect, sizeof(rect));
909}
910
reed@android.com8a1c16f2008-12-17 15:59:43 +0000911void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -0700912 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
914 }
915}
916
reed@google.com4ed0fb72012-12-12 20:48:18 +0000917void SkPictureRecord::addRRect(const SkRRect& rrect) {
918 fWriter.writeRRect(rrect);
919}
920
reed@android.com8a1c16f2008-12-17 15:59:43 +0000921void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000922 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923}
924
925void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -0700926 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000927 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000928 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000929}
930
fmalitab7425172014-08-26 07:56:44 -0700931void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -0700932 int index = fTextBlobRefs.count();
933 *fTextBlobRefs.append() = blob;
934 blob->ref();
fmalitab7425172014-08-26 07:56:44 -0700935 // follow the convention of recording a 1-based index
936 this->addInt(index + 1);
937}
938
reed@android.com8a1c16f2008-12-17 15:59:43 +0000939///////////////////////////////////////////////////////////////////////////////
940