blob: 4a6ece17f25a8ce864601ffd706cdf2ebb4aa42a [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"
reeda85d4d02015-05-06 12:56:48 -07009#include "SkImage_Base.h"
dandovb3c9d1c2014-08-12 08:34:29 -070010#include "SkPatchUtils.h"
dandovb3c9d1c2014-08-12 08:34:29 -070011#include "SkPixelRef.h"
12#include "SkRRect.h"
reed71c3c762015-06-24 10:29:17 -070013#include "SkRSXform.h"
fmalitab7425172014-08-26 07:56:44 -070014#include "SkTextBlob.h"
dandovb3c9d1c2014-08-12 08:34:29 -070015#include "SkTSearch.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
reed@android.com8a1c16f2008-12-17 15:59:43 +000017#define HEAP_BLOCK_SIZE 4096
18
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000019enum {
reed@google.comd86e7ab2012-09-27 20:31:31 +000020 // just need a value that save or getSaveCount would never return
junov@chromium.org4e6dfa52012-07-16 14:04:59 +000021 kNoInitialSave = -1,
22};
23
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +000024// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
25static int const kUInt32Size = 4;
26
robertphillips0bdbea72014-06-11 11:37:55 -070027SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
commit-bot@chromium.org19fafef2014-02-17 15:28:00 +000028 : INHERITED(dimensions.width(), dimensions.height())
mtklein71a23632014-11-12 10:24:55 -080029 , fRecordFlags(flags)
30 , fInitialSaveCount(kNoInitialSave) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000031}
32
33SkPictureRecord::~SkPictureRecord() {
robertphillips5351aad2015-06-23 06:54:56 -070034 fImageRefs.unrefAll();
djsollen@google.com21830d92012-08-07 19:49:41 +000035 fPictureRefs.unrefAll();
msarett95416f42016-04-27 13:51:20 -070036 fDrawableRefs.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
msarett95416f42016-04-27 13:51:20 -0700641void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
642 // op + drawable index
643 size_t size = 2 * kUInt32Size;
644 size_t initialOffset;
645
646 if (nullptr == matrix) {
647 initialOffset = this->addDraw(DRAW_DRAWABLE, &size);
648 this->addDrawable(drawable);
649 } else {
650 size += matrix->writeToMemory(nullptr); // matrix
651 initialOffset = this->addDraw(DRAW_DRAWABLE_MATRIX, &size);
652 this->addMatrix(*matrix);
653 this->addDrawable(drawable);
654 }
655 this->validate(initialOffset, size);
656}
657
reed41af9662015-01-05 07:49:08 -0800658void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
659 const SkPoint vertices[], const SkPoint texs[],
660 const SkColor colors[], SkXfermode* xfer,
661 const uint16_t indices[], int indexCount,
662 const SkPaint& paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663 uint32_t flags = 0;
664 if (texs) {
665 flags |= DRAW_VERTICES_HAS_TEXS;
666 }
667 if (colors) {
668 flags |= DRAW_VERTICES_HAS_COLORS;
669 }
670 if (indexCount > 0) {
671 flags |= DRAW_VERTICES_HAS_INDICES;
672 }
bsalomon49f085d2014-09-05 13:34:00 -0700673 if (xfer) {
reed@google.com85e143c2013-12-30 15:51:25 +0000674 SkXfermode::Mode mode;
675 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
676 flags |= DRAW_VERTICES_HAS_XFER;
677 }
678 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000679
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000680 // op + paint index + flags + vmode + vCount + vertices
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000681 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000682 if (flags & DRAW_VERTICES_HAS_TEXS) {
683 size += vertexCount * sizeof(SkPoint); // + uvs
684 }
685 if (flags & DRAW_VERTICES_HAS_COLORS) {
686 size += vertexCount * sizeof(SkColor); // + vert colors
687 }
688 if (flags & DRAW_VERTICES_HAS_INDICES) {
689 // + num indices + indices
690 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
691 }
reed@google.com85e143c2013-12-30 15:51:25 +0000692 if (flags & DRAW_VERTICES_HAS_XFER) {
693 size += kUInt32Size; // mode enum
694 }
robertphillips@google.com2ca1aaa2013-02-15 13:47:37 +0000695
robertphillips@google.com8b169312013-10-15 17:47:36 +0000696 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000697 this->addPaint(paint);
698 this->addInt(flags);
699 this->addInt(vmode);
700 this->addInt(vertexCount);
701 this->addPoints(vertices, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000702 if (flags & DRAW_VERTICES_HAS_TEXS) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000703 this->addPoints(texs, vertexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000704 }
705 if (flags & DRAW_VERTICES_HAS_COLORS) {
706 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
707 }
708 if (flags & DRAW_VERTICES_HAS_INDICES) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000709 this->addInt(indexCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000710 fWriter.writePad(indices, indexCount * sizeof(uint16_t));
711 }
reed@google.com85e143c2013-12-30 15:51:25 +0000712 if (flags & DRAW_VERTICES_HAS_XFER) {
713 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
714 (void)xfer->asMode(&mode);
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000715 this->addInt(mode);
reed@google.com85e143c2013-12-30 15:51:25 +0000716 }
robertphillips@google.com8b169312013-10-15 17:47:36 +0000717 this->validate(initialOffset, size);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000718}
719
dandovb3c9d1c2014-08-12 08:34:29 -0700720void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
721 const SkPoint texCoords[4], SkXfermode* xmode,
722 const SkPaint& paint) {
723 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
724 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
725 uint32_t flag = 0;
bsalomon49f085d2014-09-05 13:34:00 -0700726 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700727 flag |= DRAW_VERTICES_HAS_COLORS;
728 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
729 }
bsalomon49f085d2014-09-05 13:34:00 -0700730 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700731 flag |= DRAW_VERTICES_HAS_TEXS;
732 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
733 }
bsalomon49f085d2014-09-05 13:34:00 -0700734 if (xmode) {
dandovb3c9d1c2014-08-12 08:34:29 -0700735 SkXfermode::Mode mode;
736 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
737 flag |= DRAW_VERTICES_HAS_XFER;
738 size += kUInt32Size;
739 }
740 }
mtklein46616af2014-09-30 14:47:10 -0700741
dandov963137b2014-08-07 07:49:53 -0700742 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
dandov963137b2014-08-07 07:49:53 -0700743 this->addPaint(paint);
dandovb3c9d1c2014-08-12 08:34:29 -0700744 this->addPatch(cubics);
745 this->addInt(flag);
mtklein46616af2014-09-30 14:47:10 -0700746
dandovb3c9d1c2014-08-12 08:34:29 -0700747 // write optional parameters
bsalomon49f085d2014-09-05 13:34:00 -0700748 if (colors) {
dandovb3c9d1c2014-08-12 08:34:29 -0700749 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
750 }
bsalomon49f085d2014-09-05 13:34:00 -0700751 if (texCoords) {
dandovb3c9d1c2014-08-12 08:34:29 -0700752 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
753 }
754 if (flag & DRAW_VERTICES_HAS_XFER) {
755 SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
756 xmode->asMode(&mode);
757 this->addInt(mode);
758 }
dandov963137b2014-08-07 07:49:53 -0700759 this->validate(initialOffset, size);
760}
761
reed71c3c762015-06-24 10:29:17 -0700762void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
763 const SkColor colors[], int count, SkXfermode::Mode mode,
764 const SkRect* cull, const SkPaint* paint) {
765 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
766 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
767 uint32_t flags = 0;
768 if (colors) {
769 flags |= DRAW_ATLAS_HAS_COLORS;
770 size += count * sizeof(SkColor);
771 size += sizeof(uint32_t); // xfermode::mode
772 }
773 if (cull) {
774 flags |= DRAW_ATLAS_HAS_CULL;
775 size += sizeof(SkRect);
776 }
mtkleinc2e29772015-10-30 05:24:58 -0700777
reed71c3c762015-06-24 10:29:17 -0700778 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
reed71c3c762015-06-24 10:29:17 -0700779 this->addPaintPtr(paint);
780 this->addImage(atlas);
781 this->addInt(flags);
782 this->addInt(count);
783 fWriter.write(xform, count * sizeof(SkRSXform));
784 fWriter.write(tex, count * sizeof(SkRect));
785
786 // write optional parameters
787 if (colors) {
788 fWriter.write(colors, count * sizeof(SkColor));
789 this->addInt(mode);
790 }
791 if (cull) {
792 fWriter.write(cull, sizeof(SkRect));
793 }
794 this->validate(initialOffset, size);
795}
796
reedf70b5312016-03-04 16:36:20 -0800797void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
798 size_t keyLen = fWriter.WriteStringSize(key);
799 size_t valueLen = fWriter.WriteDataSize(value);
800 size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
801
802 size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
803 this->addRect(rect);
804 fWriter.writeString(key);
805 fWriter.writeData(value);
806 this->validate(initialOffset, size);
807}
808
reed@android.com8a1c16f2008-12-17 15:59:43 +0000809///////////////////////////////////////////////////////////////////////////////
reed@google.com82065d62011-02-07 15:30:46 +0000810
reede8f30622016-03-23 18:59:25 -0700811sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
halcanary96fcdcc2015-08-27 07:41:13 -0700812 return nullptr;
reed@google.com76f10a32014-02-05 15:32:21 +0000813}
814
mtkleine0694002014-11-12 12:49:47 -0800815// If we already have a stored, can we reuse it instead of also storing b?
816static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
817 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
818 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
819 // but it sure makes things easier to reason about below.
820 return false;
821 }
822 if (a.pixelRef() == b.pixelRef()) {
823 return true; // Same shape and same pixels -> same bitmap.
824 }
825
826 // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
827 if (!a.pixelRef() || !b.pixelRef()) {
828 return false;
829 }
830
831 // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
832 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
833 encB(b.pixelRef()->refEncodedData());
834 if (encA && encB) {
835 return encA->equals(encB);
836 } else if (encA || encB) {
837 return false; // One has encoded data but the other does not.
838 }
839
840 // As a last resort, we have to look at the pixels. This will read back textures.
841 SkAutoLockPixels al(a), bl(b);
842 const char* ap = (const char*)a.getPixels();
843 const char* bp = (const char*)b.getPixels();
844 if (ap && bp) {
845 // We check row by row; row bytes might differ.
846 SkASSERT(a.info() == b.info()); // We checked this above.
847 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true.
848 const SkImageInfo info = a.info();
849 const size_t bytesToCompare = info.width() * info.bytesPerPixel();
850 for (int row = 0; row < info.height(); row++) {
851 if (0 != memcmp(ap, bp, bytesToCompare)) {
852 return false;
853 }
854 ap += a.rowBytes();
855 bp += b.rowBytes();
856 }
857 return true;
858 }
859 return false; // Couldn't get pixels for both bitmaps.
860}
861
862void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
863 // First see if we already have this bitmap. This deduplication should really
864 // only be important for our tests, where bitmaps tend not to be tagged immutable.
865 // In Chrome (and hopefully Android?) they're typically immutable.
866 for (int i = 0; i < fBitmaps.count(); i++) {
867 if (equivalent(fBitmaps[i], bitmap)) {
868 this->addInt(i); // Unlike the rest, bitmap indices are 0-based.
869 return;
870 }
871 }
872 // Don't have it. We'll add it to our list, making sure it's tagged as immutable.
mtklein71a23632014-11-12 10:24:55 -0800873 if (bitmap.isImmutable()) {
mtkleine0694002014-11-12 12:49:47 -0800874 // Shallow copies of bitmaps are cheap, so immutable == fast.
mtklein71a23632014-11-12 10:24:55 -0800875 fBitmaps.push_back(bitmap);
876 } else {
mtkleine0694002014-11-12 12:49:47 -0800877 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
mtklein71a23632014-11-12 10:24:55 -0800878 SkBitmap copy;
879 bitmap.copyTo(&copy);
880 copy.setImmutable();
881 fBitmaps.push_back(copy);
882 }
mtkleine0694002014-11-12 12:49:47 -0800883 this->addInt(fBitmaps.count()-1); // Remember, 0-based.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000884}
885
reed871872f2015-06-22 12:48:26 -0700886void SkPictureRecord::addImage(const SkImage* image) {
887 int index = fImageRefs.find(image);
888 if (index >= 0) {
889 this->addInt(index);
890 } else {
891 *fImageRefs.append() = SkRef(image);
892 this->addInt(fImageRefs.count()-1);
893 }
894}
895
reed@android.com8a1c16f2008-12-17 15:59:43 +0000896void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000897 fWriter.writeMatrix(matrix);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000898}
899
mtklein46616af2014-09-30 14:47:10 -0700900void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
hendrikwafdada22014-08-08 10:44:33 -0700901 fContentInfo.onAddPaintPtr(paint);
commit-bot@chromium.orge2cb12a2014-04-24 21:53:13 +0000902
mtklein46616af2014-09-30 14:47:10 -0700903 if (paint) {
mtkleina74ce852014-11-12 09:19:02 -0800904 fPaints.push_back(*paint);
905 this->addInt(fPaints.count());
mtklein46616af2014-09-30 14:47:10 -0700906 } else {
907 this->addInt(0);
908 }
commit-bot@chromium.orgcf7be952013-08-22 17:19:52 +0000909}
910
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000911int SkPictureRecord::addPathToHeap(const SkPath& path) {
mtkleinc2e29772015-10-30 05:24:58 -0700912 if (int* n = fPaths.find(path)) {
913 return *n;
914 }
915 int n = fPaths.count() + 1; // 0 is reserved for null / error.
916 fPaths.set(path, n);
917 return n;
robertphillips@google.com5a63f242014-02-04 20:07:50 +0000918}
919
920void SkPictureRecord::addPath(const SkPath& path) {
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000921 this->addInt(this->addPathToHeap(path));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000922}
923
dandovb3c9d1c2014-08-12 08:34:29 -0700924void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
925 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
dandov963137b2014-08-07 07:49:53 -0700926}
927
robertphillips9b14f262014-06-04 05:40:44 -0700928void SkPictureRecord::addPicture(const SkPicture* picture) {
929 int index = fPictureRefs.find(picture);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000930 if (index < 0) { // not found
931 index = fPictureRefs.count();
robertphillips9b14f262014-06-04 05:40:44 -0700932 *fPictureRefs.append() = picture;
933 picture->ref();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000934 }
935 // follow the convention of recording a 1-based index
robertphillips@google.comcb6adec2014-02-05 14:05:38 +0000936 this->addInt(index + 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937}
938
msarett95416f42016-04-27 13:51:20 -0700939void SkPictureRecord::addDrawable(SkDrawable* drawable) {
940 int index = fDrawableRefs.find(drawable);
941 if (index < 0) { // not found
942 index = fDrawableRefs.count();
943 *fDrawableRefs.append() = drawable;
944 drawable->ref();
945 }
946 // follow the convention of recording a 1-based index
947 this->addInt(index + 1);
948}
949
reed@android.com8a1c16f2008-12-17 15:59:43 +0000950void SkPictureRecord::addPoint(const SkPoint& point) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000951 fWriter.writePoint(point);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000952}
reed@google.com82065d62011-02-07 15:30:46 +0000953
reed@android.com8a1c16f2008-12-17 15:59:43 +0000954void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
955 fWriter.writeMul4(pts, count * sizeof(SkPoint));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000956}
957
senorblanco@chromium.org68250c82014-05-06 22:52:55 +0000958void SkPictureRecord::addNoOp() {
959 size_t size = kUInt32Size; // op
960 this->addDraw(NOOP, &size);
961}
962
reed@android.com8a1c16f2008-12-17 15:59:43 +0000963void SkPictureRecord::addRect(const SkRect& rect) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 fWriter.writeRect(rect);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000965}
966
967void SkPictureRecord::addRectPtr(const SkRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -0700968 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000969 fWriter.writeRect(*rect);
970 }
971}
972
reed@google.comf0b5e112011-09-07 11:57:34 +0000973void SkPictureRecord::addIRect(const SkIRect& rect) {
974 fWriter.write(&rect, sizeof(rect));
975}
976
reed@android.com8a1c16f2008-12-17 15:59:43 +0000977void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
halcanary96fcdcc2015-08-27 07:41:13 -0700978 if (fWriter.writeBool(rect != nullptr)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000979 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
980 }
981}
982
reed@google.com4ed0fb72012-12-12 20:48:18 +0000983void SkPictureRecord::addRRect(const SkRRect& rrect) {
984 fWriter.writeRRect(rrect);
985}
986
reed@android.com8a1c16f2008-12-17 15:59:43 +0000987void SkPictureRecord::addRegion(const SkRegion& region) {
commit-bot@chromium.orgfed2ab62014-01-23 15:16:05 +0000988 fWriter.writeRegion(region);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000989}
990
991void SkPictureRecord::addText(const void* text, size_t byteLength) {
hendrikwafdada22014-08-08 10:44:33 -0700992 fContentInfo.onDrawText();
commit-bot@chromium.orgdcecb162014-04-22 17:54:29 +0000993 addInt(SkToInt(byteLength));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000994 fWriter.writePad(text, byteLength);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000995}
996
fmalitab7425172014-08-26 07:56:44 -0700997void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
jbromandd1e9f72014-09-08 13:24:33 -0700998 int index = fTextBlobRefs.count();
999 *fTextBlobRefs.append() = blob;
1000 blob->ref();
fmalitab7425172014-08-26 07:56:44 -07001001 // follow the convention of recording a 1-based index
1002 this->addInt(index + 1);
1003}
1004
reed@android.com8a1c16f2008-12-17 15:59:43 +00001005///////////////////////////////////////////////////////////////////////////////