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