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