• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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