1 /*
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 */
7
8 #include "src/core/SkPictureRecord.h"
9
10 #include "include/core/SkBlendMode.h"
11 #include "include/core/SkImageFilter.h"
12 #include "include/core/SkMatrix.h"
13 #include "include/core/SkPoint3.h"
14 #include "include/core/SkRRect.h"
15 #include "include/core/SkRSXform.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkRegion.h"
18 #include "include/core/SkShader.h"
19 #include "include/core/SkSurface.h"
20 #include "include/core/SkTextBlob.h"
21 #include "include/core/SkTileMode.h"
22 #include "include/private/base/SkPoint_impl.h"
23 #include "include/private/base/SkTo.h"
24 #include "include/private/chromium/Slug.h"
25 #include "src/core/SkCanvasPriv.h"
26 #include "src/core/SkDrawShadowInfo.h"
27 #include "src/core/SkMatrixPriv.h"
28 #include "src/core/SkSamplingPriv.h"
29 #include "src/utils/SkPatchUtils.h"
30
31 #include <utility>
32
33 class SkSurfaceProps;
34 enum class SkClipOp;
35 struct SkISize;
36 struct SkImageInfo;
37
38 using namespace skia_private;
39
40 #define HEAP_BLOCK_SIZE 4096
41
42 enum {
43 // just need a value that save or getSaveCount would never return
44 kNoInitialSave = -1,
45 };
46
47 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
48 static int const kUInt32Size = 4;
49
SkPictureRecord(const SkIRect & dimensions,uint32_t flags)50 SkPictureRecord::SkPictureRecord(const SkIRect& dimensions, uint32_t flags)
51 : SkCanvasVirtualEnforcer<SkCanvas>(dimensions)
52 , fRecordFlags(flags)
53 , fInitialSaveCount(kNoInitialSave) {
54 }
55
SkPictureRecord(const SkISize & dimensions,uint32_t flags)56 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
57 : SkPictureRecord(SkIRect::MakeSize(dimensions), flags) {}
58
willSave()59 void SkPictureRecord::willSave() {
60 // record the offset to us, making it non-positive to distinguish a save
61 // from a clip entry.
62 fRestoreOffsetStack.push_back(-(int32_t)fWriter.bytesWritten());
63 this->recordSave();
64
65 this->SkCanvasVirtualEnforcer<SkCanvas>::willSave();
66 }
67
recordSave()68 void SkPictureRecord::recordSave() {
69 // op only
70 size_t size = sizeof(kUInt32Size);
71 size_t initialOffset = this->addDraw(SAVE, &size);
72
73 this->validate(initialOffset, size);
74 }
75
getSaveLayerStrategy(const SaveLayerRec & rec)76 SkCanvas::SaveLayerStrategy SkPictureRecord::getSaveLayerStrategy(const SaveLayerRec& rec) {
77 // record the offset to us, making it non-positive to distinguish a save
78 // from a clip entry.
79 fRestoreOffsetStack.push_back(-(int32_t)fWriter.bytesWritten());
80 this->recordSaveLayer(rec);
81
82 (void)this->SkCanvasVirtualEnforcer<SkCanvas>::getSaveLayerStrategy(rec);
83 /* No need for a (potentially very big) layer which we don't actually need
84 at this time (and may not be able to afford since during record our
85 clip starts out the size of the picture, which is often much larger
86 than the size of the actual device we'll use during playback).
87 */
88 return kNoLayer_SaveLayerStrategy;
89 }
90
onDoSaveBehind(const SkRect * subset)91 bool SkPictureRecord::onDoSaveBehind(const SkRect* subset) {
92 fRestoreOffsetStack.push_back(-(int32_t)fWriter.bytesWritten());
93
94 size_t size = sizeof(kUInt32Size) + sizeof(uint32_t); // op + flags
95 uint32_t flags = 0;
96 if (subset) {
97 flags |= SAVEBEHIND_HAS_SUBSET;
98 size += sizeof(*subset);
99 }
100
101 size_t initialOffset = this->addDraw(SAVE_BEHIND, &size);
102 this->addInt(flags);
103 if (subset) {
104 this->addRect(*subset);
105 }
106
107 this->validate(initialOffset, size);
108 return false;
109 }
110
recordSaveLayer(const SaveLayerRec & rec)111 void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) {
112 // op + flatflags
113 size_t size = 2 * kUInt32Size;
114 uint32_t flatFlags = 0;
115 uint32_t filterCount = SkToU32(rec.fFilters.size());
116
117 if (rec.fBounds) {
118 flatFlags |= SAVELAYERREC_HAS_BOUNDS;
119 size += sizeof(*rec.fBounds);
120 }
121 if (rec.fPaint) {
122 flatFlags |= SAVELAYERREC_HAS_PAINT;
123 size += sizeof(uint32_t); // index
124 }
125 if (rec.fBackdrop) {
126 flatFlags |= SAVELAYERREC_HAS_BACKDROP;
127 size += sizeof(uint32_t); // (paint) index
128 }
129 if (rec.fSaveLayerFlags) {
130 flatFlags |= SAVELAYERREC_HAS_FLAGS;
131 size += sizeof(uint32_t);
132 }
133 if (SkCanvasPriv::GetBackdropScaleFactor(rec) != 1.f) {
134 flatFlags |= SAVELAYERREC_HAS_BACKDROP_SCALE;
135 size += sizeof(SkScalar);
136 }
137 if (filterCount) {
138 flatFlags |= SAVELAYERREC_HAS_MULTIPLE_FILTERS;
139 size += sizeof(uint32_t); // count
140 size += sizeof(uint32_t) * filterCount; // N (paint) indices
141 }
142 if (rec.fBackdropTileMode != SkTileMode::kClamp) {
143 flatFlags |= SAVELAYERREC_HAS_BACKDROP_TILEMODE;
144 size += sizeof(uint32_t); // SkTileMode
145 }
146
147 const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size);
148 this->addInt(flatFlags);
149 if (flatFlags & SAVELAYERREC_HAS_BOUNDS) {
150 this->addRect(*rec.fBounds);
151 }
152 if (flatFlags & SAVELAYERREC_HAS_PAINT) {
153 this->addPaintPtr(rec.fPaint);
154 }
155 if (flatFlags & SAVELAYERREC_HAS_BACKDROP) {
156 // overkill, but we didn't already track single flattenables, so using a paint for that
157 SkPaint paint;
158 paint.setImageFilter(sk_ref_sp(const_cast<SkImageFilter*>(rec.fBackdrop)));
159 this->addPaint(paint);
160 }
161 if (flatFlags & SAVELAYERREC_HAS_FLAGS) {
162 this->addInt(rec.fSaveLayerFlags);
163 }
164 if (flatFlags & SAVELAYERREC_HAS_BACKDROP_SCALE) {
165 this->addScalar(SkCanvasPriv::GetBackdropScaleFactor(rec));
166 }
167 if (flatFlags & SAVELAYERREC_HAS_MULTIPLE_FILTERS) {
168 this->addInt(filterCount);
169 for (uint32_t i = 0; i < filterCount; ++i) {
170 // overkill to store a paint, oh well.
171 SkPaint paint;
172 paint.setImageFilter(rec.fFilters[i]);
173 this->addPaint(paint);
174 }
175 }
176 if (rec.fBackdropTileMode != SkTileMode::kClamp) {
177 this->addInt((int) rec.fBackdropTileMode);
178 }
179 this->validate(initialOffset, size);
180 }
181
182 #ifdef SK_DEBUG
183 /*
184 * Read the op code from 'offset' in 'writer' and extract the size too.
185 */
peek_op_and_size(SkWriter32 * writer,size_t offset,uint32_t * size)186 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
187 uint32_t peek = writer->readTAt<uint32_t>(offset);
188
189 uint32_t op;
190 UNPACK_8_24(peek, op, *size);
191 if (MASK_24 == *size) {
192 // size required its own slot right after the op code
193 *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
194 }
195 return (DrawType) op;
196 }
197 #endif//SK_DEBUG
198
willRestore()199 void SkPictureRecord::willRestore() {
200 #if 0
201 SkASSERT(fRestoreOffsetStack.count() > 1);
202 #endif
203
204 // check for underflow
205 if (fRestoreOffsetStack.empty()) {
206 return;
207 }
208
209 this->recordRestore();
210
211 fRestoreOffsetStack.pop_back();
212
213 this->SkCanvasVirtualEnforcer<SkCanvas>::willRestore();
214 }
215
recordRestore(bool fillInSkips)216 void SkPictureRecord::recordRestore(bool fillInSkips) {
217 if (fillInSkips) {
218 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
219 }
220 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
221 size_t initialOffset = this->addDraw(RESTORE, &size);
222 this->validate(initialOffset, size);
223 }
224
recordTranslate(const SkMatrix & m)225 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
226 SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
227
228 // op + dx + dy
229 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
230 size_t initialOffset = this->addDraw(TRANSLATE, &size);
231 this->addScalar(m.getTranslateX());
232 this->addScalar(m.getTranslateY());
233 this->validate(initialOffset, size);
234 }
235
recordScale(const SkMatrix & m)236 void SkPictureRecord::recordScale(const SkMatrix& m) {
237 SkASSERT(SkMatrix::kScale_Mask == m.getType());
238
239 // op + sx + sy
240 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
241 size_t initialOffset = this->addDraw(SCALE, &size);
242 this->addScalar(m.getScaleX());
243 this->addScalar(m.getScaleY());
244 this->validate(initialOffset, size);
245 }
246
didConcat44(const SkM44 & m)247 void SkPictureRecord::didConcat44(const SkM44& m) {
248 this->validate(fWriter.bytesWritten(), 0);
249 // op + matrix
250 size_t size = kUInt32Size + 16 * sizeof(SkScalar);
251 size_t initialOffset = this->addDraw(CONCAT44, &size);
252 fWriter.write(SkMatrixPriv::M44ColMajor(m), 16 * sizeof(SkScalar));
253 this->validate(initialOffset, size);
254
255 this->SkCanvasVirtualEnforcer<SkCanvas>::didConcat44(m);
256 }
257
didSetM44(const SkM44 & m)258 void SkPictureRecord::didSetM44(const SkM44& m) {
259 this->validate(fWriter.bytesWritten(), 0);
260 // op + matrix
261 size_t size = kUInt32Size + 16 * sizeof(SkScalar);
262 size_t initialOffset = this->addDraw(SET_M44, &size);
263 fWriter.write(SkMatrixPriv::M44ColMajor(m), 16 * sizeof(SkScalar));
264 this->validate(initialOffset, size);
265 this->SkCanvasVirtualEnforcer<SkCanvas>::didSetM44(m);
266 }
267
didScale(SkScalar x,SkScalar y)268 void SkPictureRecord::didScale(SkScalar x, SkScalar y) {
269 this->didConcat44(SkM44::Scale(x, y));
270 }
271
didTranslate(SkScalar x,SkScalar y)272 void SkPictureRecord::didTranslate(SkScalar x, SkScalar y) {
273 this->didConcat44(SkM44::Translate(x, y));
274 }
275
recordConcat(const SkMatrix & matrix)276 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
277 this->validate(fWriter.bytesWritten(), 0);
278 // op + matrix
279 size_t size = kUInt32Size + SkMatrixPriv::WriteToMemory(matrix, nullptr);
280 size_t initialOffset = this->addDraw(CONCAT, &size);
281 this->addMatrix(matrix);
282 this->validate(initialOffset, size);
283 }
284
fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset)285 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
286 int32_t offset = fRestoreOffsetStack.back();
287 while (offset > 0) {
288 uint32_t peek = fWriter.readTAt<uint32_t>(offset);
289 fWriter.overwriteTAt(offset, restoreOffset);
290 offset = peek;
291 }
292
293 #ifdef SK_DEBUG
294 // offset of 0 has been disabled, so we skip it
295 if (offset > 0) {
296 // assert that the final offset value points to a save verb
297 uint32_t opSize;
298 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
299 SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERREC == drawOp);
300 }
301 #endif
302 }
303
beginRecording()304 void SkPictureRecord::beginRecording() {
305 // we have to call this *after* our constructor, to ensure that it gets
306 // recorded. This is balanced by restoreToCount() call from endRecording,
307 // which in-turn calls our overridden restore(), so those get recorded too.
308 fInitialSaveCount = this->save();
309 }
310
endRecording()311 void SkPictureRecord::endRecording() {
312 SkASSERT(kNoInitialSave != fInitialSaveCount);
313 this->restoreToCount(fInitialSaveCount);
314 }
315
recordRestoreOffsetPlaceholder()316 size_t SkPictureRecord::recordRestoreOffsetPlaceholder() {
317 if (fRestoreOffsetStack.empty()) {
318 return -1;
319 }
320
321 // The RestoreOffset field is initially filled with a placeholder
322 // value that points to the offset of the previous RestoreOffset
323 // in the current stack level, thus forming a linked list so that
324 // the restore offsets can be filled in when the corresponding
325 // restore command is recorded.
326 int32_t prevOffset = fRestoreOffsetStack.back();
327
328 size_t offset = fWriter.bytesWritten();
329 this->addInt(prevOffset);
330 fRestoreOffsetStack.back() = SkToU32(offset);
331 return offset;
332 }
333
onClipRect(const SkRect & rect,SkClipOp op,ClipEdgeStyle edgeStyle)334 void SkPictureRecord::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
335 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
336 this->SkCanvasVirtualEnforcer<SkCanvas>::onClipRect(rect, op, edgeStyle);
337 }
338
recordClipRect(const SkRect & rect,SkClipOp op,bool doAA)339 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkClipOp op, bool doAA) {
340 // id + rect + clip params
341 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
342 // recordRestoreOffsetPlaceholder doesn't always write an offset
343 if (!fRestoreOffsetStack.empty()) {
344 // + restore offset
345 size += kUInt32Size;
346 }
347 size_t initialOffset = this->addDraw(CLIP_RECT, &size);
348 this->addRect(rect);
349 this->addInt(ClipParams_pack(op, doAA));
350 size_t offset = this->recordRestoreOffsetPlaceholder();
351
352 this->validate(initialOffset, size);
353 return offset;
354 }
355
onClipRRect(const SkRRect & rrect,SkClipOp op,ClipEdgeStyle edgeStyle)356 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
357 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
358 this->SkCanvasVirtualEnforcer<SkCanvas>::onClipRRect(rrect, op, edgeStyle);
359 }
360
recordClipRRect(const SkRRect & rrect,SkClipOp op,bool doAA)361 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
362 // op + rrect + clip params
363 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
364 // recordRestoreOffsetPlaceholder doesn't always write an offset
365 if (!fRestoreOffsetStack.empty()) {
366 // + restore offset
367 size += kUInt32Size;
368 }
369 size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
370 this->addRRect(rrect);
371 this->addInt(ClipParams_pack(op, doAA));
372 size_t offset = recordRestoreOffsetPlaceholder();
373 this->validate(initialOffset, size);
374 return offset;
375 }
376
onClipPath(const SkPath & path,SkClipOp op,ClipEdgeStyle edgeStyle)377 void SkPictureRecord::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
378 int pathID = this->addPathToHeap(path);
379 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
380 this->SkCanvasVirtualEnforcer<SkCanvas>::onClipPath(path, op, edgeStyle);
381 }
382
recordClipPath(int pathID,SkClipOp op,bool doAA)383 size_t SkPictureRecord::recordClipPath(int pathID, SkClipOp op, bool doAA) {
384 // op + path index + clip params
385 size_t size = 3 * kUInt32Size;
386 // recordRestoreOffsetPlaceholder doesn't always write an offset
387 if (!fRestoreOffsetStack.empty()) {
388 // + restore offset
389 size += kUInt32Size;
390 }
391 size_t initialOffset = this->addDraw(CLIP_PATH, &size);
392 this->addInt(pathID);
393 this->addInt(ClipParams_pack(op, doAA));
394 size_t offset = recordRestoreOffsetPlaceholder();
395 this->validate(initialOffset, size);
396 return offset;
397 }
398
onClipShader(sk_sp<SkShader> cs,SkClipOp op)399 void SkPictureRecord::onClipShader(sk_sp<SkShader> cs, SkClipOp op) {
400 // Overkill to store a whole paint, but we don't have an existing structure to just store
401 // shaders. If size becomes an issue in the future, we can optimize this.
402 SkPaint paint;
403 paint.setShader(cs);
404
405 // op + paint index + clipop
406 size_t size = 3 * kUInt32Size;
407 size_t initialOffset = this->addDraw(CLIP_SHADER_IN_PAINT, &size);
408 this->addPaint(paint);
409 this->addInt((int)op);
410 this->validate(initialOffset, size);
411
412 this->SkCanvasVirtualEnforcer<SkCanvas>::onClipShader(std::move(cs), op);
413 }
414
onClipRegion(const SkRegion & region,SkClipOp op)415 void SkPictureRecord::onClipRegion(const SkRegion& region, SkClipOp op) {
416 this->recordClipRegion(region, op);
417 this->SkCanvasVirtualEnforcer<SkCanvas>::onClipRegion(region, op);
418 }
419
recordClipRegion(const SkRegion & region,SkClipOp op)420 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkClipOp op) {
421 // op + clip params + region
422 size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr);
423 // recordRestoreOffsetPlaceholder doesn't always write an offset
424 if (!fRestoreOffsetStack.empty()) {
425 // + restore offset
426 size += kUInt32Size;
427 }
428 size_t initialOffset = this->addDraw(CLIP_REGION, &size);
429 this->addRegion(region);
430 this->addInt(ClipParams_pack(op, false));
431 size_t offset = this->recordRestoreOffsetPlaceholder();
432
433 this->validate(initialOffset, size);
434 return offset;
435 }
436
onResetClip()437 void SkPictureRecord::onResetClip() {
438 if (!fRestoreOffsetStack.empty()) {
439 // Run back through any previous clip ops, and mark their offset to
440 // be 0, disabling their ability to trigger a jump-to-restore, otherwise
441 // they could hide this expansion of the clip.
442 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
443 }
444 size_t size = sizeof(kUInt32Size);
445 size_t initialOffset = this->addDraw(RESET_CLIP, &size);
446 this->validate(initialOffset, size);
447 this->SkCanvasVirtualEnforcer<SkCanvas>::onResetClip();
448 }
449
onDrawPaint(const SkPaint & paint)450 void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
451 // op + paint index
452 size_t size = 2 * kUInt32Size;
453 size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
454 this->addPaint(paint);
455 this->validate(initialOffset, size);
456 }
457
onDrawBehind(const SkPaint & paint)458 void SkPictureRecord::onDrawBehind(const SkPaint& paint) {
459 // logically the same as drawPaint, but with a diff enum
460 // op + paint index
461 size_t size = 2 * kUInt32Size;
462 size_t initialOffset = this->addDraw(DRAW_BEHIND_PAINT, &size);
463 this->addPaint(paint);
464 this->validate(initialOffset, size);
465 }
466
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)467 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
468 const SkPaint& paint) {
469 // op + paint index + mode + count + point data
470 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
471 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
472 this->addPaint(paint);
473
474 this->addInt(mode);
475 this->addInt(SkToInt(count));
476 fWriter.writeMul4(pts, count * sizeof(SkPoint));
477 this->validate(initialOffset, size);
478 }
479
onDrawOval(const SkRect & oval,const SkPaint & paint)480 void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
481 // op + paint index + rect
482 size_t size = 2 * kUInt32Size + sizeof(oval);
483 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
484 this->addPaint(paint);
485 this->addRect(oval);
486 this->validate(initialOffset, size);
487 }
488
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)489 void SkPictureRecord::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
490 bool useCenter, const SkPaint& paint) {
491 // op + paint index + rect + start + sweep + bool (as int)
492 size_t size = 2 * kUInt32Size + sizeof(oval) + sizeof(startAngle) + sizeof(sweepAngle) +
493 sizeof(int);
494 size_t initialOffset = this->addDraw(DRAW_ARC, &size);
495 this->addPaint(paint);
496 this->addRect(oval);
497 this->addScalar(startAngle);
498 this->addScalar(sweepAngle);
499 this->addInt(useCenter);
500 this->validate(initialOffset, size);
501 }
502
onDrawRect(const SkRect & rect,const SkPaint & paint)503 void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
504 // op + paint index + rect
505 size_t size = 2 * kUInt32Size + sizeof(rect);
506 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
507 this->addPaint(paint);
508 this->addRect(rect);
509 this->validate(initialOffset, size);
510 }
511
onDrawRegion(const SkRegion & region,const SkPaint & paint)512 void SkPictureRecord::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
513 // op + paint index + region
514 size_t regionBytes = region.writeToMemory(nullptr);
515 size_t size = 2 * kUInt32Size + regionBytes;
516 size_t initialOffset = this->addDraw(DRAW_REGION, &size);
517 this->addPaint(paint);
518 fWriter.writeRegion(region);
519 this->validate(initialOffset, size);
520 }
521
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)522 void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
523 // op + paint index + rrect
524 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
525 size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
526 this->addPaint(paint);
527 this->addRRect(rrect);
528 this->validate(initialOffset, size);
529 }
530
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)531 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
532 const SkPaint& paint) {
533 // op + paint index + rrects
534 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
535 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
536 this->addPaint(paint);
537 this->addRRect(outer);
538 this->addRRect(inner);
539 this->validate(initialOffset, size);
540 }
541
onDrawPath(const SkPath & path,const SkPaint & paint)542 void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
543 // op + paint index + path index
544 size_t size = 3 * kUInt32Size;
545 size_t initialOffset = this->addDraw(DRAW_PATH, &size);
546 this->addPaint(paint);
547 this->addPath(path);
548 this->validate(initialOffset, size);
549 }
550
onDrawImage2(const SkImage * image,SkScalar x,SkScalar y,const SkSamplingOptions & sampling,const SkPaint * paint)551 void SkPictureRecord::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
552 const SkSamplingOptions& sampling, const SkPaint* paint) {
553 // op + paint_index + image_index + x + y
554 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar) + SkSamplingPriv::FlatSize(sampling);
555 size_t initialOffset = this->addDraw(DRAW_IMAGE2, &size);
556 this->addPaintPtr(paint);
557 this->addImage(image);
558 this->addScalar(x);
559 this->addScalar(y);
560 this->addSampling(sampling);
561 this->validate(initialOffset, size);
562 }
563
onDrawImageRect2(const SkImage * image,const SkRect & src,const SkRect & dst,const SkSamplingOptions & sampling,const SkPaint * paint,SrcRectConstraint constraint)564 void SkPictureRecord::onDrawImageRect2(const SkImage* image, const SkRect& src, const SkRect& dst,
565 const SkSamplingOptions& sampling, const SkPaint* paint,
566 SrcRectConstraint constraint) {
567 // id + paint_index + image_index + constraint
568 size_t size = 3 * kUInt32Size + 2 * sizeof(dst) + SkSamplingPriv::FlatSize(sampling) +
569 kUInt32Size;
570
571 size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT2, &size);
572 this->addPaintPtr(paint);
573 this->addImage(image);
574 this->addRect(src);
575 this->addRect(dst);
576 this->addSampling(sampling);
577 this->addInt(constraint);
578 this->validate(initialOffset, size);
579 }
580
onDrawImageLattice2(const SkImage * image,const Lattice & lattice,const SkRect & dst,SkFilterMode filter,const SkPaint * paint)581 void SkPictureRecord::onDrawImageLattice2(const SkImage* image, const Lattice& lattice,
582 const SkRect& dst, SkFilterMode filter,
583 const SkPaint* paint) {
584 size_t latticeSize = SkCanvasPriv::WriteLattice(nullptr, lattice);
585 // op + paint index + image index + lattice + dst rect
586 size_t size = 3 * kUInt32Size + latticeSize + sizeof(dst) + sizeof(uint32_t); // filter
587 size_t initialOffset = this->addDraw(DRAW_IMAGE_LATTICE2, &size);
588 this->addPaintPtr(paint);
589 this->addImage(image);
590 (void)SkCanvasPriv::WriteLattice(fWriter.reservePad(latticeSize), lattice);
591 this->addRect(dst);
592 this->addInt(static_cast<uint32_t>(filter));
593 this->validate(initialOffset, size);
594 }
595
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)596 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
597 const SkPaint& paint) {
598
599 // op + paint index + blob index + x/y
600 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
601 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
602
603 this->addPaint(paint);
604 this->addTextBlob(blob);
605 this->addScalar(x);
606 this->addScalar(y);
607
608 this->validate(initialOffset, size);
609 }
610
onDrawSlug(const sktext::gpu::Slug * slug,const SkPaint & paint)611 void SkPictureRecord::onDrawSlug(const sktext::gpu::Slug* slug, const SkPaint& paint) {
612 // op + paint index + slug id
613 size_t size = 3 * kUInt32Size;
614 size_t initialOffset = this->addDraw(DRAW_SLUG, &size);
615
616 this->addPaint(paint);
617 this->addSlug(slug);
618 this->validate(initialOffset, size);
619 }
620
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)621 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
622 const SkPaint* paint) {
623 // op + picture index
624 size_t size = 2 * kUInt32Size;
625 size_t initialOffset;
626
627 if (nullptr == matrix && nullptr == paint) {
628 initialOffset = this->addDraw(DRAW_PICTURE, &size);
629 this->addPicture(picture);
630 } else {
631 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
632 size += SkMatrixPriv::WriteToMemory(m, nullptr) + kUInt32Size; // matrix + paint
633 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
634 this->addPaintPtr(paint);
635 this->addMatrix(m);
636 this->addPicture(picture);
637 }
638 this->validate(initialOffset, size);
639 }
640
onDrawDrawable(SkDrawable * drawable,const SkMatrix * matrix)641 void 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 += SkMatrixPriv::WriteToMemory(*matrix, 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
onDrawVerticesObject(const SkVertices * vertices,SkBlendMode mode,const SkPaint & paint)658 void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices,
659 SkBlendMode mode, const SkPaint& paint) {
660 // op + paint index + vertices index + zero_bones + mode
661 size_t size = 5 * kUInt32Size;
662 size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size);
663
664 this->addPaint(paint);
665 this->addVertices(vertices);
666 this->addInt(0); // legacy bone count
667 this->addInt(static_cast<uint32_t>(mode));
668
669 this->validate(initialOffset, size);
670 }
671
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)672 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
673 const SkPoint texCoords[4], SkBlendMode bmode,
674 const SkPaint& paint) {
675 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
676 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
677 uint32_t flag = 0;
678 if (colors) {
679 flag |= DRAW_VERTICES_HAS_COLORS;
680 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
681 }
682 if (texCoords) {
683 flag |= DRAW_VERTICES_HAS_TEXS;
684 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
685 }
686 if (SkBlendMode::kModulate != bmode) {
687 flag |= DRAW_VERTICES_HAS_XFER;
688 size += kUInt32Size;
689 }
690
691 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
692 this->addPaint(paint);
693 this->addPatch(cubics);
694 this->addInt(flag);
695
696 // write optional parameters
697 if (colors) {
698 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
699 }
700 if (texCoords) {
701 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
702 }
703 if (flag & DRAW_VERTICES_HAS_XFER) {
704 this->addInt((int)bmode);
705 }
706 this->validate(initialOffset, size);
707 }
708
onDrawAtlas2(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkSamplingOptions & sampling,const SkRect * cull,const SkPaint * paint)709 void SkPictureRecord::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
710 const SkColor colors[], int count, SkBlendMode mode,
711 const SkSamplingOptions& sampling, const SkRect* cull,
712 const SkPaint* paint) {
713 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
714 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
715 size += SkSamplingPriv::FlatSize(sampling);
716 uint32_t flags = 0;
717 if (colors) {
718 flags |= DRAW_ATLAS_HAS_COLORS;
719 size += count * sizeof(SkColor);
720 size += sizeof(uint32_t); // xfermode::mode
721 }
722 if (cull) {
723 flags |= DRAW_ATLAS_HAS_CULL;
724 size += sizeof(SkRect);
725 }
726 flags |= DRAW_ATLAS_HAS_SAMPLING;
727
728 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
729 this->addPaintPtr(paint);
730 this->addImage(atlas);
731 this->addInt(flags);
732 this->addInt(count);
733 fWriter.write(xform, count * sizeof(SkRSXform));
734 fWriter.write(tex, count * sizeof(SkRect));
735
736 // write optional parameters
737 if (colors) {
738 fWriter.write(colors, count * sizeof(SkColor));
739 this->addInt((int)mode);
740 }
741 if (cull) {
742 fWriter.write(cull, sizeof(SkRect));
743 }
744 this->addSampling(sampling);
745 this->validate(initialOffset, size);
746 }
747
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)748 void SkPictureRecord::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
749 // op + path index + zParams + lightPos + lightRadius + spot/ambient alphas + color + flags
750 size_t size = 2 * kUInt32Size + 2 * sizeof(SkPoint3) + 1 * sizeof(SkScalar) + 3 * kUInt32Size;
751 size_t initialOffset = this->addDraw(DRAW_SHADOW_REC, &size);
752
753 this->addPath(path);
754
755 fWriter.writePoint3(rec.fZPlaneParams);
756 fWriter.writePoint3(rec.fLightPos);
757 fWriter.writeScalar(rec.fLightRadius);
758 fWriter.write32(rec.fAmbientColor);
759 fWriter.write32(rec.fSpotColor);
760 fWriter.write32(rec.fFlags);
761
762 this->validate(initialOffset, size);
763 }
764
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)765 void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
766 size_t keyLen = SkWriter32::WriteStringSize(key);
767 size_t valueLen = SkWriter32::WriteDataSize(value);
768 size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
769
770 size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
771 this->addRect(rect);
772 fWriter.writeString(key);
773 fWriter.writeData(value);
774 this->validate(initialOffset, size);
775 }
776
onDrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aa,const SkColor4f & color,SkBlendMode mode)777 void SkPictureRecord::onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
778 SkCanvas::QuadAAFlags aa, const SkColor4f& color,
779 SkBlendMode mode) {
780
781 // op + rect + aa flags + color + mode + hasClip(as int) + clipCount*points
782 size_t size = 4 * kUInt32Size + sizeof(SkColor4f) + sizeof(rect) +
783 (clip ? 4 : 0) * sizeof(SkPoint);
784 size_t initialOffset = this->addDraw(DRAW_EDGEAA_QUAD, &size);
785 this->addRect(rect);
786 this->addInt((int) aa);
787 fWriter.write(&color, sizeof(SkColor4f));
788 this->addInt((int) mode);
789 this->addInt(clip != nullptr);
790 if (clip) {
791 this->addPoints(clip, 4);
792 }
793 this->validate(initialOffset, size);
794 }
795
onDrawEdgeAAImageSet2(const SkCanvas::ImageSetEntry set[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkSamplingOptions & sampling,const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)796 void SkPictureRecord::onDrawEdgeAAImageSet2(const SkCanvas::ImageSetEntry set[], int count,
797 const SkPoint dstClips[],
798 const SkMatrix preViewMatrices[],
799 const SkSamplingOptions& sampling,
800 const SkPaint* paint,
801 SkCanvas::SrcRectConstraint constraint) {
802 static constexpr size_t kMatrixSize = 9 * sizeof(SkScalar); // *not* sizeof(SkMatrix)
803 // op + count + paint + constraint + (image index, src rect, dst rect, alpha, aa flags,
804 // hasClip(int), matrixIndex) * cnt + totalClipCount + dstClips + totalMatrixCount + matrices
805 int totalDstClipCount, totalMatrixCount;
806 SkCanvasPriv::GetDstClipAndMatrixCounts(set, count, &totalDstClipCount, &totalMatrixCount);
807
808 size_t size = 6 * kUInt32Size + sizeof(SkPoint) * totalDstClipCount +
809 kMatrixSize * totalMatrixCount +
810 (4 * kUInt32Size + 2 * sizeof(SkRect) + sizeof(SkScalar)) * count +
811 SkSamplingPriv::FlatSize(sampling);
812 size_t initialOffset = this->addDraw(DRAW_EDGEAA_IMAGE_SET2, &size);
813 this->addInt(count);
814 this->addPaintPtr(paint);
815 this->addSampling(sampling);
816 this->addInt((int) constraint);
817 for (int i = 0; i < count; ++i) {
818 this->addImage(set[i].fImage.get());
819 this->addRect(set[i].fSrcRect);
820 this->addRect(set[i].fDstRect);
821 this->addInt(set[i].fMatrixIndex);
822 this->addScalar(set[i].fAlpha);
823 this->addInt((int)set[i].fAAFlags);
824 this->addInt(set[i].fHasClip);
825 }
826 this->addInt(totalDstClipCount);
827 this->addPoints(dstClips, totalDstClipCount);
828 this->addInt(totalMatrixCount);
829 for (int i = 0; i < totalMatrixCount; ++i) {
830 this->addMatrix(preViewMatrices[i]);
831 }
832 this->validate(initialOffset, size);
833 }
834
835 ///////////////////////////////////////////////////////////////////////////////
836
837 // De-duping helper.
838
839 template <typename T>
equals(T * a,T * b)840 static bool equals(T* a, T* b) { return a->uniqueID() == b->uniqueID(); }
841
842 template <>
equals(SkDrawable * a,SkDrawable * b)843 bool equals(SkDrawable* a, SkDrawable* b) {
844 // SkDrawable's generationID is not a stable unique identifier.
845 return a == b;
846 }
847
848 template <typename T>
find_or_append(TArray<sk_sp<T>> & array,T * obj)849 static int find_or_append(TArray<sk_sp<T>>& array, T* obj) {
850 for (int i = 0; i < array.size(); i++) {
851 if (equals(array[i].get(), obj)) {
852 return i;
853 }
854 }
855
856 array.push_back(sk_ref_sp(obj));
857
858 return array.size() - 1;
859 }
860
onNewSurface(const SkImageInfo & info,const SkSurfaceProps &)861 sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
862 return nullptr;
863 }
864
addImage(const SkImage * image)865 void SkPictureRecord::addImage(const SkImage* image) {
866 // convention for images is 0-based index
867 this->addInt(find_or_append(fImages, image));
868 }
869
addMatrix(const SkMatrix & matrix)870 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
871 fWriter.writeMatrix(matrix);
872 }
873
addPaintPtr(const SkPaint * paint)874 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
875 if (paint) {
876 fPaints.push_back(*paint);
877 this->addInt(fPaints.size());
878 } else {
879 this->addInt(0);
880 }
881 }
882
addPathToHeap(const SkPath & path)883 int SkPictureRecord::addPathToHeap(const SkPath& path) {
884 if (int* n = fPaths.find(path)) {
885 return *n;
886 }
887 int n = fPaths.count() + 1; // 0 is reserved for null / error.
888 fPaths.set(path, n);
889 return n;
890 }
891
addPath(const SkPath & path)892 void SkPictureRecord::addPath(const SkPath& path) {
893 this->addInt(this->addPathToHeap(path));
894 }
895
addPatch(const SkPoint cubics[12])896 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
897 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
898 }
899
addPicture(const SkPicture * picture)900 void SkPictureRecord::addPicture(const SkPicture* picture) {
901 // follow the convention of recording a 1-based index
902 this->addInt(find_or_append(fPictures, picture) + 1);
903 }
904
addDrawable(SkDrawable * drawable)905 void SkPictureRecord::addDrawable(SkDrawable* drawable) {
906 // follow the convention of recording a 1-based index
907 this->addInt(find_or_append(fDrawables, drawable) + 1);
908 }
909
addPoint(const SkPoint & point)910 void SkPictureRecord::addPoint(const SkPoint& point) {
911 fWriter.writePoint(point);
912 }
913
addPoints(const SkPoint pts[],int count)914 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
915 fWriter.writeMul4(pts, count * sizeof(SkPoint));
916 }
917
addNoOp()918 void SkPictureRecord::addNoOp() {
919 size_t size = kUInt32Size; // op
920 this->addDraw(NOOP, &size);
921 }
922
addRect(const SkRect & rect)923 void SkPictureRecord::addRect(const SkRect& rect) {
924 fWriter.writeRect(rect);
925 }
926
addRectPtr(const SkRect * rect)927 void SkPictureRecord::addRectPtr(const SkRect* rect) {
928 if (fWriter.writeBool(rect != nullptr)) {
929 fWriter.writeRect(*rect);
930 }
931 }
932
addIRect(const SkIRect & rect)933 void SkPictureRecord::addIRect(const SkIRect& rect) {
934 fWriter.write(&rect, sizeof(rect));
935 }
936
addIRectPtr(const SkIRect * rect)937 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
938 if (fWriter.writeBool(rect != nullptr)) {
939 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
940 }
941 }
942
addRRect(const SkRRect & rrect)943 void SkPictureRecord::addRRect(const SkRRect& rrect) {
944 fWriter.writeRRect(rrect);
945 }
946
addRegion(const SkRegion & region)947 void SkPictureRecord::addRegion(const SkRegion& region) {
948 fWriter.writeRegion(region);
949 }
950
addSampling(const SkSamplingOptions & sampling)951 void SkPictureRecord::addSampling(const SkSamplingOptions& sampling) {
952 fWriter.writeSampling(sampling);
953 }
954
addText(const void * text,size_t byteLength)955 void SkPictureRecord::addText(const void* text, size_t byteLength) {
956 addInt(SkToInt(byteLength));
957 fWriter.writePad(text, byteLength);
958 }
959
addTextBlob(const SkTextBlob * blob)960 void SkPictureRecord::addTextBlob(const SkTextBlob* blob) {
961 // follow the convention of recording a 1-based index
962 this->addInt(find_or_append(fTextBlobs, blob) + 1);
963 }
964
addSlug(const sktext::gpu::Slug * slug)965 void SkPictureRecord::addSlug(const sktext::gpu::Slug* slug) {
966 // follow the convention of recording a 1-based index
967 this->addInt(find_or_append(fSlugs, slug) + 1);
968 }
969
addVertices(const SkVertices * vertices)970 void SkPictureRecord::addVertices(const SkVertices* vertices) {
971 // follow the convention of recording a 1-based index
972 this->addInt(find_or_append(fVertices, vertices) + 1);
973 }
974