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