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