xref: /aosp_15_r20/external/skia/src/core/SkPictureRecord.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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