blob: 459402b1150cb32070d022c1f60d7e33fce887f8 [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
reedbfd5f172016-01-07 11:28:08 -080079 // op + flatflags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +000080 size_t size = 2 * kUInt32Size;
reedbfd5f172016-01-07 11:28:08 -080081 uint32_t flatFlags = 0;
82
reed4960eee2015-12-18 07:09:18 -080083 if (rec.fBounds) {
reedbfd5f172016-01-07 11:28:08 -080084 flatFlags |= SAVELAYERREC_HAS_BOUNDS;
85 size += sizeof(*rec.fBounds);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000086 }
reedbfd5f172016-01-07 11:28:08 -080087 if (rec.fPaint) {
88 flatFlags |= SAVELAYERREC_HAS_PAINT;
89 size += sizeof(uint32_t); // index
90 }
91 if (rec.fBackdrop) {
92 flatFlags |= SAVELAYERREC_HAS_BACKDROP;
93 size += sizeof(uint32_t); // (paint) index
94 }
95 if (rec.fSaveLayerFlags) {
96 flatFlags |= SAVELAYERREC_HAS_FLAGS;
97 size += sizeof(uint32_t);
98 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000099
reedbfd5f172016-01-07 11:28:08 -0800100 const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size);
101 this->addInt(flatFlags);
102 if (flatFlags & SAVELAYERREC_HAS_BOUNDS) {
103 this->addRect(*rec.fBounds);
104 }
105 if (flatFlags & SAVELAYERREC_HAS_PAINT) {
106 this->addPaintPtr(rec.fPaint);
107 }
108 if (flatFlags & SAVELAYERREC_HAS_BACKDROP) {
109 // overkill, but we didn't already track single flattenables, so using a paint for that
110 SkPaint paint;
111 paint.setImageFilter(const_cast<SkImageFilter*>(rec.fBackdrop));
112 this->addPaint(paint);
113 }
114 if (flatFlags & SAVELAYERREC_HAS_FLAGS) {
115 this->addInt(rec.fSaveLayerFlags);
116 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000117 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118}
119
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000120#ifdef SK_DEBUG
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000121/*
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000122 * Read the op code from 'offset' in 'writer' and extract the size too.
123 */
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000124static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000125 uint32_t peek = writer->readTAt<uint32_t>(offset);
reed@google.comffacd3c2012-08-30 15:31:23 +0000126
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000127 uint32_t op;
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000128 UNPACK_8_24(peek, op, *size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000129 if (MASK_24 == *size) {
130 // size required its own slot right after the op code
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000131 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000132 }
133 return (DrawType) op;
reed@google.comffacd3c2012-08-30 15:31:23 +0000134}
mtklein46616af2014-09-30 14:47:10 -0700135#endif//SK_DEBUG
commit-bot@chromium.org4b32bd52013-03-15 15:06:03 +0000136
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000137void SkPictureRecord::willRestore() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000138#if 0
139 SkASSERT(fRestoreOffsetStack.count() > 1);
140#endif
141
reed@android.comb4e22d62009-07-09 15:20:25 +0000142 // check for underflow
143 if (fRestoreOffsetStack.count() == 0) {
144 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000145 }
reed@android.comb4e22d62009-07-09 15:20:25 +0000146
mtklein46616af2014-09-30 14:47:10 -0700147 this->recordRestore();
reed@google.comffacd3c2012-08-30 15:31:23 +0000148
reed@android.comb4e22d62009-07-09 15:20:25 +0000149 fRestoreOffsetStack.pop();
reed@android.com32a42492009-07-10 03:33:52 +0000150
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000151 this->INHERITED::willRestore();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152}
153
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000154void SkPictureRecord::recordRestore(bool fillInSkips) {
robertphillipsc019ec42014-08-12 05:35:58 -0700155 fContentInfo.onRestore();
156
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000157 if (fillInSkips) {
158 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
159 }
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000160 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
161 size_t initialOffset = this->addDraw(RESTORE, &size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000162 this->validate(initialOffset, size);
163}
164
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000165void SkPictureRecord::recordTranslate(const SkMatrix& m) {
166 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
167
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000168 // op + dx + dy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000169 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000170 size_t initialOffset = this->addDraw(TRANSLATE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000171 this->addScalar(m.getTranslateX());
172 this->addScalar(m.getTranslateY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000173 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000174}
175
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000176void SkPictureRecord::recordScale(const SkMatrix& m) {
177 SkASSERT(SkMatrix::kScale_Mask == m.getType());
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000178
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000179 // op + sx + sy
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000180 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000181 size_t initialOffset = this->addDraw(SCALE, &size);
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000182 this->addScalar(m.getScaleX());
183 this->addScalar(m.getScaleY());
robertphillips@google.com8b169312013-10-15 17:47:36 +0000184 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185}
186
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000187void SkPictureRecord::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000188 switch (matrix.getType()) {
189 case SkMatrix::kTranslate_Mask:
190 this->recordTranslate(matrix);
191 break;
192 case SkMatrix::kScale_Mask:
193 this->recordScale(matrix);
194 break;
195 default:
196 this->recordConcat(matrix);
197 break;
198 }
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000199 this->INHERITED::didConcat(matrix);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000200}
201
202void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000203 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000204 // op + matrix
halcanary96fcdcc2015-08-27 07:41:13 -0700205 size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000206 size_t initialOffset = this->addDraw(CONCAT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000207 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000208 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209}
210
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000211void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
reed@google.com44699382013-10-31 17:28:30 +0000212 this->validate(fWriter.bytesWritten(), 0);
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000213 // op + matrix
halcanary96fcdcc2015-08-27 07:41:13 -0700214 size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000215 size_t initialOffset = this->addDraw(SET_MATRIX, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000216 this->addMatrix(matrix);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000217 this->validate(initialOffset, size);
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000218 this->INHERITED::didSetMatrix(matrix);
reed@android.com6e073b92009-01-06 15:03:30 +0000219}
220
reed@google.com45482d12011-08-29 19:02:39 +0000221static bool regionOpExpands(SkRegion::Op op) {
222 switch (op) {
223 case SkRegion::kUnion_Op:
224 case SkRegion::kXOR_Op:
225 case SkRegion::kReverseDifference_Op:
226 case SkRegion::kReplace_Op:
227 return true;
228 case SkRegion::kIntersect_Op:
229 case SkRegion::kDifference_Op:
230 return false;
231 default:
tomhudson@google.com0c00f212011-12-28 14:59:50 +0000232 SkDEBUGFAIL("unknown region op");
reed@google.com45482d12011-08-29 19:02:39 +0000233 return false;
234 }
235}
236
robertphillips@google.come37ad352013-03-01 19:44:30 +0000237void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
reed@google.comffacd3c2012-08-30 15:31:23 +0000238 int32_t offset = fRestoreOffsetStack.top();
239 while (offset > 0) {
commit-bot@chromium.org536ac5e2014-02-11 22:38:51 +0000240 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
241 fWriter.overwriteTAt(offset, restoreOffset);
commit-bot@chromium.orgc6d3c442014-01-31 16:22:57 +0000242 offset = peek;
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000243 }
skia.committer@gmail.com11f86922012-08-31 17:14:46 +0000244
reed@google.comffacd3c2012-08-30 15:31:23 +0000245#ifdef SK_DEBUG
reed2ff1fce2014-12-11 07:07:37 -0800246 // offset of 0 has been disabled, so we skip it
247 if (offset > 0) {
248 // assert that the final offset value points to a save verb
249 uint32_t opSize;
250 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
reed4960eee2015-12-18 07:09:18 -0800251 SkASSERT(SAVE_LAYER_SAVEFLAGS_DEPRECATED != drawOp);
reedbfd5f172016-01-07 11:28:08 -0800252 SkASSERT(SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016 != drawOp);
253 SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERREC == drawOp);
reed2ff1fce2014-12-11 07:07:37 -0800254 }
reed@google.comffacd3c2012-08-30 15:31:23 +0000255#endif
junov@chromium.orge3dbedb2012-07-09 16:03:55 +0000256}
257
reed@google.comd86e7ab2012-09-27 20:31:31 +0000258void SkPictureRecord::beginRecording() {
259 // we have to call this *after* our constructor, to ensure that it gets
260 // recorded. This is balanced by restoreToCount() call from endRecording,
261 // which in-turn calls our overridden restore(), so those get recorded too.
commit-bot@chromium.org091a5942014-04-18 14:19:31 +0000262 fInitialSaveCount = this->save();
reed@google.comd86e7ab2012-09-27 20:31:31 +0000263}
264
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000265void SkPictureRecord::endRecording() {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000266 SkASSERT(kNoInitialSave != fInitialSaveCount);
267 this->restoreToCount(fInitialSaveCount);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000268}
269
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000270size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
reed@google.com21b519d2012-10-02 17:42:15 +0000271 if (fRestoreOffsetStack.isEmpty()) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000272 return -1;
reed@google.com21b519d2012-10-02 17:42:15 +0000273 }
274
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000275 // The RestoreOffset field is initially filled with a placeholder
276 // value that points to the offset of the previous RestoreOffset
277 // in the current stack level, thus forming a linked list so that
278 // the restore offsets can be filled in when the corresponding
279 // restore command is recorded.
280 int32_t prevOffset = fRestoreOffsetStack.top();
281
reed@google.com45482d12011-08-29 19:02:39 +0000282 if (regionOpExpands(op)) {
283 // Run back through any previous clip ops, and mark their offset to
284 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
285 // they could hide this clips ability to expand the clip (i.e. go from
286 // empty to non-empty).
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000287 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
fmalita@google.comd0f1a4f2013-08-27 15:50:19 +0000288
289 // Reset the pointer back to the previous clip so that subsequent
290 // restores don't overwrite the offsets we just cleared.
291 prevOffset = 0;
reed@google.com45482d12011-08-29 19:02:39 +0000292 }
vandebo@chromium.org74b46192012-01-28 01:45:11 +0000293
reed@google.com44699382013-10-31 17:28:30 +0000294 size_t offset = fWriter.bytesWritten();
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000295 this->addInt(prevOffset);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000296 fRestoreOffsetStack.top() = SkToU32(offset);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000297 return offset;
reed@google.com45482d12011-08-29 19:02:39 +0000298}
299
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000300void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000301 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000302 this->INHERITED::onClipRect(rect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000303}
304
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000305size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000306 // id + rect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000307 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000308 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000309 if (!fRestoreOffsetStack.isEmpty()) {
310 // + restore offset
311 size += kUInt32Size;
312 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000313 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000314 this->addRect(rect);
315 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000316 size_t offset = this->recordRestoreOffsetPlaceholder(op);
skia.committer@gmail.com306ab9d2012-12-13 02:01:33 +0000317
robertphillips@google.com8b169312013-10-15 17:47:36 +0000318 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000319 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320}
321
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000322void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000323 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700324 this->INHERITED::onClipRRect(rrect, op, edgeStyle);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000325}
326
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000327size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
robertphillips@google.comf9291502013-02-15 15:13:27 +0000328 // op + rrect + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000329 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
robertphillips@google.com4310c662013-03-01 14:17:58 +0000330 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000331 if (!fRestoreOffsetStack.isEmpty()) {
332 // + restore offset
333 size += kUInt32Size;
334 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000335 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000336 this->addRRect(rrect);
337 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000338 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000339 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000340 return offset;
reed@google.com4ed0fb72012-12-12 20:48:18 +0000341}
342
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000343void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000344 int pathID = this->addPathToHeap(path);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000345 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
reedd9544982014-09-09 18:46:22 -0700346 this->INHERITED::onClipPath(path, op, edgeStyle);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347}
348
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000349size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000350 // op + path index + clip params
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000351 size_t size = 3 * kUInt32Size;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000352 // recordRestoreOffsetPlaceholder doesn't always write an offset
353 if (!fRestoreOffsetStack.isEmpty()) {
354 // + restore offset
355 size += kUInt32Size;
356 }
357 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000358 this->addInt(pathID);
359 this->addInt(ClipParams_pack(op, doAA));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000360 size_t offset = recordRestoreOffsetPlaceholder(op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000361 this->validate(initialOffset, size);
362 return offset;
363}
364
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000365void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000366 this->recordClipRegion(region, op);
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000367 this->INHERITED::onClipRegion(region, op);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000368}
369
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000370size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000371 // op + clip params + region
halcanary96fcdcc2015-08-27 07:41:13 -0700372 size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr);
robertphillips@google.com4310c662013-03-01 14:17:58 +0000373 // recordRestoreOffsetPlaceholder doesn't always write an offset
robertphillips@google.comf9291502013-02-15 15:13:27 +0000374 if (!fRestoreOffsetStack.isEmpty()) {
375 // + restore offset
376 size += kUInt32Size;
377 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000378 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000379 this->addRegion(region);
380 this->addInt(ClipParams_pack(op, false));
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000381 size_t offset = this->recordRestoreOffsetPlaceholder(op);
reed@google.com82065d62011-02-07 15:30:46 +0000382
robertphillips@google.com8b169312013-10-15 17:47:36 +0000383 this->validate(initialOffset, size);
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000384 return offset;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000385}
386
reed41af9662015-01-05 07:49:08 -0800387void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000388 // op + paint index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000389 size_t size = 2 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000390 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000391 this->addPaint(paint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000392 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000393}
394
reed41af9662015-01-05 07:49:08 -0800395void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
396 const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700397 fContentInfo.onDrawPoints(count, paint);
robertphillips@google.com105a4a52014-02-11 15:10:40 +0000398
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000399 // op + paint index + mode + count + point data
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000400 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000401 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000402 this->addPaint(paint);
hendrikwafdada22014-08-08 10:44:33 -0700403
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000404 this->addInt(mode);
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000405 this->addInt(SkToInt(count));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000406 fWriter.writeMul4(pts, count * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000407 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000408}
409
reed41af9662015-01-05 07:49:08 -0800410void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000411 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000412 size_t size = 2 * kUInt32Size + sizeof(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000413 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000414 this->addPaint(paint);
415 this->addRect(oval);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000416 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000417}
418
reed41af9662015-01-05 07:49:08 -0800419void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000420 // op + paint index + rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000421 size_t size = 2 * kUInt32Size + sizeof(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000422 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000423 this->addPaint(paint);
424 this->addRect(rect);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000425 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000426}
427
reed41af9662015-01-05 07:49:08 -0800428void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
mtklein46616af2014-09-30 14:47:10 -0700429 // op + paint index + rrect
430 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
431 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
mtklein46616af2014-09-30 14:47:10 -0700432 this->addPaint(paint);
433 this->addRRect(rrect);
434 this->validate(initialOffset, size);
reed@google.com4ed0fb72012-12-12 20:48:18 +0000435}
436
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000437void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
438 const SkPaint& paint) {
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000439 // op + paint index + rrects
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000440 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
441 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
commit-bot@chromium.orged9806f2014-02-21 02:32:36 +0000442 this->addPaint(paint);
443 this->addRRect(outer);
444 this->addRRect(inner);
445 this->validate(initialOffset, size);
446}
447
reed41af9662015-01-05 07:49:08 -0800448void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
hendrikwafdada22014-08-08 10:44:33 -0700449 fContentInfo.onDrawPath(path, paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000450
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000451 // op + paint index + path index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000452 size_t size = 3 * kUInt32Size;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000453 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000454 this->addPaint(paint);
455 this->addPath(path);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000456 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000457}
458
reed41af9662015-01-05 07:49:08 -0800459void SkPictureRecord::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
460 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000461 // op + paint index + bitmap index + left + top
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000462 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000463 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000464 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000465 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000466 this->addScalar(left);
467 this->addScalar(top);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000468 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000469}
470
reed41af9662015-01-05 07:49:08 -0800471void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700472 const SkPaint* paint, SrcRectConstraint constraint) {
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000473 // id + paint index + bitmap index + bool for 'src' + flags
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000474 size_t size = 5 * kUInt32Size;
bsalomon49f085d2014-09-05 13:34:00 -0700475 if (src) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000476 size += sizeof(*src); // + rect
477 }
478 size += sizeof(dst); // + rect
479
reeda5517e22015-07-14 10:54:12 -0700480 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000481 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000482 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000483 this->addRectPtr(src); // may be null
484 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700485 this->addInt(constraint);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000486 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000487}
488
reeda85d4d02015-05-06 12:56:48 -0700489void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
490 const SkPaint* paint) {
reed871872f2015-06-22 12:48:26 -0700491 // op + paint_index + image_index + x + y
492 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
493 size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
reed871872f2015-06-22 12:48:26 -0700494 this->addPaintPtr(paint);
495 this->addImage(image);
496 this->addScalar(x);
497 this->addScalar(y);
498 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700499}
500
501void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700502 const SkPaint* paint, SrcRectConstraint constraint) {
reeda5517e22015-07-14 10:54:12 -0700503 // id + paint_index + image_index + bool_for_src + constraint
504 size_t size = 5 * kUInt32Size;
reed871872f2015-06-22 12:48:26 -0700505 if (src) {
506 size += sizeof(*src); // + rect
reeda85d4d02015-05-06 12:56:48 -0700507 }
reed871872f2015-06-22 12:48:26 -0700508 size += sizeof(dst); // + rect
mtkleinc2e29772015-10-30 05:24:58 -0700509
reed871872f2015-06-22 12:48:26 -0700510 size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
reed871872f2015-06-22 12:48:26 -0700511 this->addPaintPtr(paint);
512 this->addImage(image);
513 this->addRectPtr(src); // may be null
514 this->addRect(dst);
reeda5517e22015-07-14 10:54:12 -0700515 this->addInt(constraint);
reed871872f2015-06-22 12:48:26 -0700516 this->validate(initialOffset, size);
reeda85d4d02015-05-06 12:56:48 -0700517}
518
reed4c21dc52015-06-25 12:32:03 -0700519void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
520 const SkPaint* paint) {
521 // id + paint_index + image_index + center + dst
522 size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
mtkleinc2e29772015-10-30 05:24:58 -0700523
reed4c21dc52015-06-25 12:32:03 -0700524 size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
reed4c21dc52015-06-25 12:32:03 -0700525 this->addPaintPtr(paint);
526 this->addImage(img);
527 this->addIRect(center);
528 this->addRect(dst);
529 this->validate(initialOffset, size);
530}
531
reed41af9662015-01-05 07:49:08 -0800532void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
533 const SkRect& dst, const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000534 // op + paint index + bitmap id + center + dst rect
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000535 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000536 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000537 this->addPaintPtr(paint);
commit-bot@chromium.orgf6a5afb2014-04-14 15:02:50 +0000538 this->addBitmap(bitmap);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000539 this->addIRect(center);
540 this->addRect(dst);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000541 this->validate(initialOffset, size);
reed@google.comf0b5e112011-09-07 11:57:34 +0000542}
543
reed@google.come0d9ce82014-04-23 04:00:17 +0000544void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
545 const SkPaint& paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000546 // op + paint index + length + 'length' worth of chars + x + y
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000547 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000548
mtklein46616af2014-09-30 14:47:10 -0700549 DrawType op = DRAW_TEXT;
robertphillips@google.com8b169312013-10-15 17:47:36 +0000550 size_t initialOffset = this->addDraw(op, &size);
mtklein46616af2014-09-30 14:47:10 -0700551 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000552 this->addText(text, byteLength);
553 this->addScalar(x);
554 this->addScalar(y);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000555 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000556}
557
reed@google.come0d9ce82014-04-23 04:00:17 +0000558void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
559 const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000560 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000561
mtklein46616af2014-09-30 14:47:10 -0700562 // op + paint index + length + 'length' worth of data + num points + x&y point data
563 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
reed@google.com82065d62011-02-07 15:30:46 +0000564
mtklein46616af2014-09-30 14:47:10 -0700565 DrawType op = DRAW_POS_TEXT;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000566
robertphillips@google.com8b169312013-10-15 17:47:36 +0000567 size_t initialOffset = this->addDraw(op, &size);
mtklein46616af2014-09-30 14:47:10 -0700568 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000569 this->addText(text, byteLength);
570 this->addInt(points);
mtklein46616af2014-09-30 14:47:10 -0700571 fWriter.writeMul4(pos, points * sizeof(SkPoint));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000572 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573}
574
reed@google.come0d9ce82014-04-23 04:00:17 +0000575void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
576 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000577 int points = paint.countText(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000578
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000579 // op + paint index + length + 'length' worth of data + num points
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000580 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000581 // + y + the actual points
582 size += 1 * kUInt32Size + points * sizeof(SkScalar);
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000583
mtklein46616af2014-09-30 14:47:10 -0700584 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
585 this->addPaint(paint);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000586 this->addText(text, byteLength);
587 this->addInt(points);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000588 this->addScalar(constY);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000589 fWriter.writeMul4(xpos, points * sizeof(SkScalar));
robertphillips@google.com8b169312013-10-15 17:47:36 +0000590 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591}
592
reed@google.come0d9ce82014-04-23 04:00:17 +0000593void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
594 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000595 // op + paint index + length + 'length' worth of data + path index + matrix
596 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
halcanary96fcdcc2015-08-27 07:41:13 -0700597 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(nullptr);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000598 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000599 this->addPaint(paint);
600 this->addText(text, byteLength);
601 this->addPath(path);
602 this->addMatrix(m);
robertphillips@google.com8b169312013-10-15 17:47:36 +0000603 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604}
605
fmalitab7425172014-08-26 07:56:44 -0700606void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
607 const SkPaint& paint) {
608
609 // op + paint index + blob index + x/y
610 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
611 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
fmalitab7425172014-08-26 07:56:44 -0700612
613 this->addPaint(paint);
614 this->addTextBlob(blob);
615 this->addScalar(x);
616 this->addScalar(y);
617
618 this->validate(initialOffset, size);
619}
620
reedd5fa1a42014-08-09 11:08:05 -0700621void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
622 const SkPaint* paint) {
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000623 // op + picture index
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000624 size_t size = 2 * kUInt32Size;
reedd5fa1a42014-08-09 11:08:05 -0700625 size_t initialOffset;
626
halcanary96fcdcc2015-08-27 07:41:13 -0700627 if (nullptr == matrix && nullptr == paint) {
reedd5fa1a42014-08-09 11:08:05 -0700628 initialOffset = this->addDraw(DRAW_PICTURE, &size);
629 this->addPicture(picture);
630 } else {
631 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
halcanary96fcdcc2015-08-27 07:41:13 -0700632 size += m.writeToMemory(nullptr) + kUInt32Size; // matrix + paint
reedd5fa1a42014-08-09 11:08:05 -0700633 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
reedd5fa1a42014-08-09 11:08:05 -0700634 this->addPaintPtr(paint);
fmalita9f49cfd2014-08-12 12:24:17 -0700635 this->addMatrix(m);
636 this->addPicture(picture);
reedd5fa1a42014-08-09 11:08:05 -0700637 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000638 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000639}
640
reed41af9662015-01-05 07:49:08 -0800641void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
642 const SkPoint vertices[], const SkPoint texs[],
643 const SkColor colors[], SkXfermode* xfer,
644 const uint16_t indices[], int indexCount,
645 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000646 uint32_t flags = 0;
647 if (texs) {
648 flags |= DRAW_VERTICES_HAS_TEXS;
649 }
650 if (colors) {
651 flags |= DRAW_VERTICES_HAS_COLORS;
652 }
653 if (indexCount > 0) {
654 flags |= DRAW_VERTICES_HAS_INDICES;
655 }
bsalomon49f085d2014-09-05 13:34:00 -0700656 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +0000657 SkXfermode::Mode mode;
658 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
659 flags |= DRAW_VERTICES_HAS_XFER;
660 }
661 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000662
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000663 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000664 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000665 if (flags & DRAW_VERTICES_HAS_TEXS) {
666 size += vertexCount * sizeof(SkPoint); // + uvs
667 }
668 if (flags & DRAW_VERTICES_HAS_COLORS) {
669 size += vertexCount * sizeof(SkColor); // + vert colors
670 }
671 if (flags & DRAW_VERTICES_HAS_INDICES) {
672 // + num indices + indices
673 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
674 }
reed@google.com85e143c2013-12-30 15:51:25 +0000675 if (flags & DRAW_VERTICES_HAS_XFER) {
676 size += kUInt32Size; // mode enum
677 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000678
robertphillips@google.com8b169312013-10-15 17:47:36 +0000679 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000680 this->addPaint(paint);
681 this->addInt(flags);
682 this->addInt(vmode);
683 this->addInt(vertexCount);
684 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000686 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 }
688 if (flags & DRAW_VERTICES_HAS_COLORS) {
689 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
690 }
691 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000692 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000693 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
694 }
reed@google.com85e143c2013-12-30 15:51:25 +0000695 if (flags & DRAW_VERTICES_HAS_XFER) {
696 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
697 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000698 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +0000699 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000700 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000701}
702
dandovb3c9d1c2014-08-12 08:34:29 -0700703void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
704 const SkPoint texCoords[4], SkXfermode* xmode,
705 const SkPaint& paint) {
706 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
707 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
708 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -0700709 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700710 flag |= DRAW_VERTICES_HAS_COLORS;
711 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
712 }
bsalomon49f085d2014-09-05 13:34:00 -0700713 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700714 flag |= DRAW_VERTICES_HAS_TEXS;
715 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
716 }
bsalomon49f085d2014-09-05 13:34:00 -0700717 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -0700718 SkXfermode::Mode mode;
719 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
720 flag |= DRAW_VERTICES_HAS_XFER;
721 size += kUInt32Size;
722 }
723 }
mtklein46616af2014-09-30 14:47:10 -0700724
dandov963137b2014-08-07 07:49:53 -0700725 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
dandov963137b2014-08-07 07:49:53 -0700726 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -0700727 this->addPatch(cubics);
728 this->addInt(flag);
mtklein46616af2014-09-30 14:47:10 -0700729
dandovb3c9d1c2014-08-12 08:34:29 -0700730 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -0700731 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700732 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
733 }
bsalomon49f085d2014-09-05 13:34:00 -0700734 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700735 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
736 }
737 if (flag & DRAW_VERTICES_HAS_XFER) {
738 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
739 xmode->asMode(&mode);
740 this->addInt(mode);
741 }
dandov963137b2014-08-07 07:49:53 -0700742 this->validate(initialOffset, size);
743}
744
reed71c3c762015-06-24 10:29:17 -0700745void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
746 const SkColor colors[], int count, SkXfermode::Mode mode,
747 const SkRect* cull, const SkPaint* paint) {
748 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
749 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
750 uint32_t flags = 0;
751 if (colors) {
752 flags |= DRAW_ATLAS_HAS_COLORS;
753 size += count * sizeof(SkColor);
754 size += sizeof(uint32_t); // xfermode::mode
755 }
756 if (cull) {
757 flags |= DRAW_ATLAS_HAS_CULL;
758 size += sizeof(SkRect);
759 }
mtkleinc2e29772015-10-30 05:24:58 -0700760
reed71c3c762015-06-24 10:29:17 -0700761 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
reed71c3c762015-06-24 10:29:17 -0700762 this->addPaintPtr(paint);
763 this->addImage(atlas);
764 this->addInt(flags);
765 this->addInt(count);
766 fWriter.write(xform, count * sizeof(SkRSXform));
767 fWriter.write(tex, count * sizeof(SkRect));
768
769 // write optional parameters
770 if (colors) {
771 fWriter.write(colors, count * sizeof(SkColor));
772 this->addInt(mode);
773 }
774 if (cull) {
775 fWriter.write(cull, sizeof(SkRect));
776 }
777 this->validate(initialOffset, size);
778}
779
reedf70b5312016-03-04 16:36:20 -0800780void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
781 size_t keyLen = fWriter.WriteStringSize(key);
782 size_t valueLen = fWriter.WriteDataSize(value);
783 size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
784
785 size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
786 this->addRect(rect);
787 fWriter.writeString(key);
788 fWriter.writeData(value);
789 this->validate(initialOffset, size);
790}
791
reed@android.com8a1c16f2008-12-17 15:59:43 +0000792///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000793
reede8f30622016-03-23 18:59:25 -0700794sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
halcanary96fcdcc2015-08-27 07:41:13 -0700795 return nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +0000796}
797
mtkleine0694002014-11-12 12:49:47 -0800798// If we already have a stored, can we reuse it instead of also storing b?
799static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
800 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
801 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
802 // but it sure makes things easier to reason about below.
803 return false;
804 }
805 if (a.pixelRef() == b.pixelRef()) {
806 return true; // Same shape and same pixels -> same bitmap.
807 }
808
809 // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
810 if (!a.pixelRef() || !b.pixelRef()) {
811 return false;
812 }
813
814 // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
815 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
816 encB(b.pixelRef()->refEncodedData());
817 if (encA && encB) {
818 return encA->equals(encB);
819 } else if (encA || encB) {
820 return false; // One has encoded data but the other does not.
821 }
822
823 // As a last resort, we have to look at the pixels. This will read back textures.
824 SkAutoLockPixels al(a), bl(b);
825 const char* ap = (const char*)a.getPixels();
826 const char* bp = (const char*)b.getPixels();
827 if (ap && bp) {
828 // We check row by row; row bytes might differ.
829 SkASSERT(a.info() == b.info()); // We checked this above.
830 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true.
831 const SkImageInfo info = a.info();
832 const size_t bytesToCompare = info.width() * info.bytesPerPixel();
833 for (int row = 0; row < info.height(); row++) {
834 if (0 != memcmp(ap, bp, bytesToCompare)) {
835 return false;
836 }
837 ap += a.rowBytes();
838 bp += b.rowBytes();
839 }
840 return true;
841 }
842 return false; // Couldn't get pixels for both bitmaps.
843}
844
845void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
846 // First see if we already have this bitmap. This deduplication should really
847 // only be important for our tests, where bitmaps tend not to be tagged immutable.
848 // In Chrome (and hopefully Android?) they're typically immutable.
849 for (int i = 0; i < fBitmaps.count(); i++) {
850 if (equivalent(fBitmaps[i], bitmap)) {
851 this->addInt(i); // Unlike the rest, bitmap indices are 0-based.
852 return;
853 }
854 }
855 // Don't have it. We'll add it to our list, making sure it's tagged as immutable.
mtklein71a23632014-11-12 10:24:55 -0800856 if (bitmap.isImmutable()) {
mtkleine0694002014-11-12 12:49:47 -0800857 // Shallow copies of bitmaps are cheap, so immutable == fast.
mtklein71a23632014-11-12 10:24:55 -0800858 fBitmaps.push_back(bitmap);
859 } else {
mtkleine0694002014-11-12 12:49:47 -0800860 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
mtklein71a23632014-11-12 10:24:55 -0800861 SkBitmap copy;
862 bitmap.copyTo(&copy);
863 copy.setImmutable();
864 fBitmaps.push_back(copy);
865 }
mtkleine0694002014-11-12 12:49:47 -0800866 this->addInt(fBitmaps.count()-1); // Remember, 0-based.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000867}
868
reed871872f2015-06-22 12:48:26 -0700869void SkPictureRecord::addImage(const SkImage* image) {
870 int index = fImageRefs.find(image);
871 if (index >= 0) {
872 this->addInt(index);
873 } else {
874 *fImageRefs.append() = SkRef(image);
875 this->addInt(fImageRefs.count()-1);
876 }
877}
878
reed@android.com8a1c16f2008-12-17 15:59:43 +0000879void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000880 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881}
882
mtklein46616af2014-09-30 14:47:10 -0700883void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -0700884 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000885
mtklein46616af2014-09-30 14:47:10 -0700886 if (paint) {
mtkleina74ce852014-11-12 09:19:02 -0800887 fPaints.push_back(*paint);
888 this->addInt(fPaints.count());
mtklein46616af2014-09-30 14:47:10 -0700889 } else {
890 this->addInt(0);
891 }
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000892}
893
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000894int SkPictureRecord::addPathToHeap(const SkPath& path) {
mtkleinc2e29772015-10-30 05:24:58 -0700895 if (int* n = fPaths.find(path)) {
896 return *n;
897 }
898 int n = fPaths.count() + 1; // 0 is reserved for null / error.
899 fPaths.set(path, n);
900 return n;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000901}
902
903void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000904 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000905}
906
dandovb3c9d1c2014-08-12 08:34:29 -0700907void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
908 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -0700909}
910
robertphillips9b14f262014-06-04 05:40:44 -0700911void SkPictureRecord::addPicture(const SkPicture* picture) {
912 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000913 if (index < 0) { // not found
914 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -0700915 *fPictureRefs.append() = picture;
916 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000917 }
918 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000919 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000920}
921
922void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000923 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000924}
reed@google.com82065d62011-02-07 15:30:46 +0000925
reed@android.com8a1c16f2008-12-17 15:59:43 +0000926void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
927 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000928}
929
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000930void SkPictureRecord::addNoOp() {
931 size_t size = kUInt32Size; // op
932 this->addDraw(NOOP, &size);
933}
934
reed@android.com8a1c16f2008-12-17 15:59:43 +0000935void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000936 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937}
938
939void SkPictureRecord::addRectPtr(const SkRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -0700940 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941 fWriter.writeRect(*rect);
942 }
943}
944
reed@google.comf0b5e112011-09-07 11:57:34 +0000945void SkPictureRecord::addIRect(const SkIRect& rect) {
946 fWriter.write(&rect, sizeof(rect));
947}
948
reed@android.com8a1c16f2008-12-17 15:59:43 +0000949void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -0700950 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000951 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
952 }
953}
954
reed@google.com4ed0fb72012-12-12 20:48:18 +0000955void SkPictureRecord::addRRect(const SkRRect& rrect) {
956 fWriter.writeRRect(rrect);
957}
958
reed@android.com8a1c16f2008-12-17 15:59:43 +0000959void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000960 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000961}
962
963void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -0700964 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000965 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000967}
968
fmalitab7425172014-08-26 07:56:44 -0700969void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -0700970 int index = fTextBlobRefs.count();
971 *fTextBlobRefs.append() = blob;
972 blob->ref();
fmalitab7425172014-08-26 07:56:44 -0700973 // follow the convention of recording a 1-based index
974 this->addInt(index + 1);
975}
976
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977///////////////////////////////////////////////////////////////////////////////
978