• 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/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 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 
onDrawBehind(const SkPaint & paint)425 void SkPictureRecord::onDrawBehind(const SkPaint& paint) {
426     // logically the same as drawPaint, but with a diff enum
427     // op + paint index
428     size_t size = 2 * kUInt32Size;
429     size_t initialOffset = this->addDraw(DRAW_BEHIND_PAINT, &size);
430     this->addPaint(paint);
431     this->validate(initialOffset, size);
432 }
433 
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)434 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
435                                    const SkPaint& paint) {
436     // op + paint index + mode + count + point data
437     size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
438     size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
439     this->addPaint(paint);
440 
441     this->addInt(mode);
442     this->addInt(SkToInt(count));
443     fWriter.writeMul4(pts, count * sizeof(SkPoint));
444     this->validate(initialOffset, size);
445 }
446 
onDrawOval(const SkRect & oval,const SkPaint & paint)447 void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
448     // op + paint index + rect
449     size_t size = 2 * kUInt32Size + sizeof(oval);
450     size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
451     this->addPaint(paint);
452     this->addRect(oval);
453     this->validate(initialOffset, size);
454 }
455 
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)456 void SkPictureRecord::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
457                                 bool useCenter, const SkPaint& paint) {
458     // op + paint index + rect + start + sweep + bool (as int)
459     size_t size = 2 * kUInt32Size + sizeof(oval) + sizeof(startAngle) + sizeof(sweepAngle) +
460                   sizeof(int);
461     size_t initialOffset = this->addDraw(DRAW_ARC, &size);
462     this->addPaint(paint);
463     this->addRect(oval);
464     this->addScalar(startAngle);
465     this->addScalar(sweepAngle);
466     this->addInt(useCenter);
467     this->validate(initialOffset, size);
468 }
469 
onDrawRect(const SkRect & rect,const SkPaint & paint)470 void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
471     // op + paint index + rect
472     size_t size = 2 * kUInt32Size + sizeof(rect);
473     size_t initialOffset = this->addDraw(DRAW_RECT, &size);
474     this->addPaint(paint);
475     this->addRect(rect);
476     this->validate(initialOffset, size);
477 }
478 
onDrawRegion(const SkRegion & region,const SkPaint & paint)479 void SkPictureRecord::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
480     // op + paint index + region
481     size_t regionBytes = region.writeToMemory(nullptr);
482     size_t size = 2 * kUInt32Size + regionBytes;
483     size_t initialOffset = this->addDraw(DRAW_REGION, &size);
484     this->addPaint(paint);
485     fWriter.writeRegion(region);
486     this->validate(initialOffset, size);
487 }
488 
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)489 void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
490     // op + paint index + rrect
491     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
492     size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
493     this->addPaint(paint);
494     this->addRRect(rrect);
495     this->validate(initialOffset, size);
496 }
497 
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)498 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
499                                    const SkPaint& paint) {
500     // op + paint index + rrects
501     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
502     size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
503     this->addPaint(paint);
504     this->addRRect(outer);
505     this->addRRect(inner);
506     this->validate(initialOffset, size);
507 }
508 
onDrawPath(const SkPath & path,const SkPaint & paint)509 void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
510     // op + paint index + path index
511     size_t size = 3 * kUInt32Size;
512     size_t initialOffset = this->addDraw(DRAW_PATH, &size);
513     this->addPaint(paint);
514     this->addPath(path);
515     this->validate(initialOffset, size);
516 }
517 
onDrawImage(const SkImage * image,SkScalar x,SkScalar y,const SkPaint * paint)518 void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
519                                   const SkPaint* paint) {
520     // op + paint_index + image_index + x + y
521     size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
522     size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
523     this->addPaintPtr(paint);
524     this->addImage(image);
525     this->addScalar(x);
526     this->addScalar(y);
527     this->validate(initialOffset, size);
528 }
529 
onDrawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint,SrcRectConstraint constraint)530 void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
531                                       const SkPaint* paint, SrcRectConstraint constraint) {
532     // id + paint_index + image_index + bool_for_src + constraint
533     size_t size = 5 * kUInt32Size;
534     if (src) {
535         size += sizeof(*src);   // + rect
536     }
537     size += sizeof(dst);        // + rect
538 
539     size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
540     this->addPaintPtr(paint);
541     this->addImage(image);
542     this->addRectPtr(src);  // may be null
543     this->addRect(dst);
544     this->addInt(constraint);
545     this->validate(initialOffset, size);
546 }
547 
onDrawImageNine(const SkImage * img,const SkIRect & center,const SkRect & dst,const SkPaint * paint)548 void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
549                                       const SkPaint* paint) {
550     // id + paint_index + image_index + center + dst
551     size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
552 
553     size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
554     this->addPaintPtr(paint);
555     this->addImage(img);
556     this->addIRect(center);
557     this->addRect(dst);
558     this->validate(initialOffset, size);
559 }
560 
onDrawImageLattice(const SkImage * image,const Lattice & lattice,const SkRect & dst,const SkPaint * paint)561 void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
562                                          const SkRect& dst, const SkPaint* paint) {
563     size_t latticeSize = SkCanvasPriv::WriteLattice(nullptr, lattice);
564     // op + paint index + image index + lattice + dst rect
565     size_t size = 3 * kUInt32Size + latticeSize + sizeof(dst);
566     size_t initialOffset = this->addDraw(DRAW_IMAGE_LATTICE, &size);
567     this->addPaintPtr(paint);
568     this->addImage(image);
569     (void)SkCanvasPriv::WriteLattice(fWriter.reservePad(latticeSize), lattice);
570     this->addRect(dst);
571     this->validate(initialOffset, size);
572 }
573 
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)574 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
575                                      const SkPaint& paint) {
576 
577     // op + paint index + blob index + x/y
578     size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
579     size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
580 
581     this->addPaint(paint);
582     this->addTextBlob(blob);
583     this->addScalar(x);
584     this->addScalar(y);
585 
586     this->validate(initialOffset, size);
587 }
588 
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)589 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
590                                     const SkPaint* paint) {
591     // op + picture index
592     size_t size = 2 * kUInt32Size;
593     size_t initialOffset;
594 
595     if (nullptr == matrix && nullptr == paint) {
596         initialOffset = this->addDraw(DRAW_PICTURE, &size);
597         this->addPicture(picture);
598     } else {
599         const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
600         size += SkMatrixPriv::WriteToMemory(m, nullptr) + kUInt32Size;    // matrix + paint
601         initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
602         this->addPaintPtr(paint);
603         this->addMatrix(m);
604         this->addPicture(picture);
605     }
606     this->validate(initialOffset, size);
607 }
608 
onDrawDrawable(SkDrawable * drawable,const SkMatrix * matrix)609 void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
610     // op + drawable index
611     size_t size = 2 * kUInt32Size;
612     size_t initialOffset;
613 
614     if (nullptr == matrix) {
615         initialOffset = this->addDraw(DRAW_DRAWABLE, &size);
616         this->addDrawable(drawable);
617     } else {
618         size += SkMatrixPriv::WriteToMemory(*matrix, nullptr);    // matrix
619         initialOffset = this->addDraw(DRAW_DRAWABLE_MATRIX, &size);
620         this->addMatrix(*matrix);
621         this->addDrawable(drawable);
622     }
623     this->validate(initialOffset, size);
624 }
625 
onDrawVerticesObject(const SkVertices * vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode mode,const SkPaint & paint)626 void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices,
627                                            const SkVertices::Bone bones[], int boneCount,
628                                            SkBlendMode mode, const SkPaint& paint) {
629     // op + paint index + vertices index + number of bones + bone matrices + mode
630     size_t size = 5 * kUInt32Size + boneCount * sizeof(SkVertices::Bone);
631     size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size);
632 
633     this->addPaint(paint);
634     this->addVertices(vertices);
635     this->addInt(boneCount);
636     fWriter.write(bones, boneCount * sizeof(SkVertices::Bone));
637     this->addInt(static_cast<uint32_t>(mode));
638 
639     this->validate(initialOffset, size);
640 }
641 
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)642 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
643                                   const SkPoint texCoords[4], SkBlendMode bmode,
644                                   const SkPaint& paint) {
645     // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
646     size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
647     uint32_t flag = 0;
648     if (colors) {
649         flag |= DRAW_VERTICES_HAS_COLORS;
650         size += SkPatchUtils::kNumCorners * sizeof(SkColor);
651     }
652     if (texCoords) {
653         flag |= DRAW_VERTICES_HAS_TEXS;
654         size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
655     }
656     if (SkBlendMode::kModulate != bmode) {
657         flag |= DRAW_VERTICES_HAS_XFER;
658         size += kUInt32Size;
659     }
660 
661     size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
662     this->addPaint(paint);
663     this->addPatch(cubics);
664     this->addInt(flag);
665 
666     // write optional parameters
667     if (colors) {
668         fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
669     }
670     if (texCoords) {
671         fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
672     }
673     if (flag & DRAW_VERTICES_HAS_XFER) {
674         this->addInt((int)bmode);
675     }
676     this->validate(initialOffset, size);
677 }
678 
onDrawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkRect * cull,const SkPaint * paint)679 void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
680                                   const SkColor colors[], int count, SkBlendMode mode,
681                                   const SkRect* cull, const SkPaint* paint) {
682     // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
683     size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
684     uint32_t flags = 0;
685     if (colors) {
686         flags |= DRAW_ATLAS_HAS_COLORS;
687         size += count * sizeof(SkColor);
688         size += sizeof(uint32_t);   // xfermode::mode
689     }
690     if (cull) {
691         flags |= DRAW_ATLAS_HAS_CULL;
692         size += sizeof(SkRect);
693     }
694 
695     size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
696     this->addPaintPtr(paint);
697     this->addImage(atlas);
698     this->addInt(flags);
699     this->addInt(count);
700     fWriter.write(xform, count * sizeof(SkRSXform));
701     fWriter.write(tex, count * sizeof(SkRect));
702 
703     // write optional parameters
704     if (colors) {
705         fWriter.write(colors, count * sizeof(SkColor));
706         this->addInt((int)mode);
707     }
708     if (cull) {
709         fWriter.write(cull, sizeof(SkRect));
710     }
711     this->validate(initialOffset, size);
712 }
713 
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)714 void SkPictureRecord::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
715     // op + path index + zParams + lightPos + lightRadius + spot/ambient alphas + color + flags
716     size_t size = 2 * kUInt32Size + 2 * sizeof(SkPoint3) + 1 * sizeof(SkScalar) + 3 * kUInt32Size;
717     size_t initialOffset = this->addDraw(DRAW_SHADOW_REC, &size);
718 
719     this->addPath(path);
720 
721     fWriter.writePoint3(rec.fZPlaneParams);
722     fWriter.writePoint3(rec.fLightPos);
723     fWriter.writeScalar(rec.fLightRadius);
724     fWriter.write32(rec.fAmbientColor);
725     fWriter.write32(rec.fSpotColor);
726     fWriter.write32(rec.fFlags);
727 
728     this->validate(initialOffset, size);
729 }
730 
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)731 void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
732     size_t keyLen = fWriter.WriteStringSize(key);
733     size_t valueLen = fWriter.WriteDataSize(value);
734     size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
735 
736     size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
737     this->addRect(rect);
738     fWriter.writeString(key);
739     fWriter.writeData(value);
740     this->validate(initialOffset, size);
741 }
742 
onDrawEdgeAAQuad(const SkRect & rect,const SkPoint clip[4],SkCanvas::QuadAAFlags aa,SkColor color,SkBlendMode mode)743 void SkPictureRecord::onDrawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
744                                        SkCanvas::QuadAAFlags aa, SkColor color, SkBlendMode mode) {
745 
746     // op + rect + aa flags + color + mode + hasClip(as int) + clipCount*points
747     size_t size = 5 * kUInt32Size + sizeof(rect) + (clip ? 4 : 0) * sizeof(SkPoint);
748     size_t initialOffset = this->addDraw(DRAW_EDGEAA_QUAD, &size);
749     this->addRect(rect);
750     this->addInt((int) aa);
751     this->addInt((int) color);
752     this->addInt((int) mode);
753     this->addInt(clip != nullptr);
754     if (clip) {
755         this->addPoints(clip, 4);
756     }
757     this->validate(initialOffset, size);
758 }
759 
onDrawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[],int count,const SkPoint dstClips[],const SkMatrix preViewMatrices[],const SkPaint * paint,SkCanvas::SrcRectConstraint constraint)760 void SkPictureRecord::onDrawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[], int count,
761                                            const SkPoint dstClips[],
762                                            const SkMatrix preViewMatrices[],
763                                            const SkPaint* paint,
764                                            SkCanvas::SrcRectConstraint constraint) {
765     static constexpr size_t kMatrixSize = 9 * sizeof(SkScalar); // *not* sizeof(SkMatrix)
766     // op + count + paint + constraint + (image index, src rect, dst rect, alpha, aa flags,
767     // hasClip(int), matrixIndex) * cnt + totalClipCount + dstClips + totalMatrixCount + matrices
768     int totalDstClipCount, totalMatrixCount;
769     SkCanvasPriv::GetDstClipAndMatrixCounts(set, count, &totalDstClipCount, &totalMatrixCount);
770 
771     size_t size = 6 * kUInt32Size + sizeof(SkPoint) * totalDstClipCount +
772                   kMatrixSize * totalMatrixCount +
773                   (4 * kUInt32Size + 2 * sizeof(SkRect) + sizeof(SkScalar)) * count;
774     size_t initialOffset = this->addDraw(DRAW_EDGEAA_IMAGE_SET, &size);
775     this->addInt(count);
776     this->addPaintPtr(paint);
777     this->addInt((int) constraint);
778     for (int i = 0; i < count; ++i) {
779         this->addImage(set[i].fImage.get());
780         this->addRect(set[i].fSrcRect);
781         this->addRect(set[i].fDstRect);
782         this->addInt(set[i].fMatrixIndex);
783         this->addScalar(set[i].fAlpha);
784         this->addInt((int)set[i].fAAFlags);
785         this->addInt(set[i].fHasClip);
786     }
787     this->addInt(totalDstClipCount);
788     this->addPoints(dstClips, totalDstClipCount);
789     this->addInt(totalMatrixCount);
790     for (int i = 0; i < totalMatrixCount; ++i) {
791         this->addMatrix(preViewMatrices[i]);
792     }
793     this->validate(initialOffset, size);
794 }
795 
796 ///////////////////////////////////////////////////////////////////////////////
797 
798 // De-duping helper.
799 
800 template <typename T>
equals(T * a,T * b)801 static bool equals(T* a, T* b) { return a->uniqueID() == b->uniqueID(); }
802 
803 template <>
equals(SkDrawable * a,SkDrawable * b)804 bool equals(SkDrawable* a, SkDrawable* b) {
805     // SkDrawable's generationID is not a stable unique identifier.
806     return a == b;
807 }
808 
809 template <typename T>
find_or_append(SkTArray<sk_sp<T>> & array,T * obj)810 static int find_or_append(SkTArray<sk_sp<T>>& array, T* obj) {
811     for (int i = 0; i < array.count(); i++) {
812         if (equals(array[i].get(), obj)) {
813             return i;
814         }
815     }
816 
817     array.push_back(sk_ref_sp(obj));
818 
819     return array.count() - 1;
820 }
821 
onNewSurface(const SkImageInfo & info,const SkSurfaceProps &)822 sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
823     return nullptr;
824 }
825 
addImage(const SkImage * image)826 void SkPictureRecord::addImage(const SkImage* image) {
827     // convention for images is 0-based index
828     this->addInt(find_or_append(fImages, image));
829 }
830 
addMatrix(const SkMatrix & matrix)831 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
832     fWriter.writeMatrix(matrix);
833 }
834 
addPaintPtr(const SkPaint * paint)835 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
836     if (paint) {
837         fPaints.push_back(*paint);
838         this->addInt(fPaints.count());
839     } else {
840         this->addInt(0);
841     }
842 }
843 
addPathToHeap(const SkPath & path)844 int SkPictureRecord::addPathToHeap(const SkPath& path) {
845     if (int* n = fPaths.find(path)) {
846         return *n;
847     }
848     int n = fPaths.count() + 1;  // 0 is reserved for null / error.
849     fPaths.set(path, n);
850     return n;
851 }
852 
addPath(const SkPath & path)853 void SkPictureRecord::addPath(const SkPath& path) {
854     this->addInt(this->addPathToHeap(path));
855 }
856 
addPatch(const SkPoint cubics[12])857 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
858     fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
859 }
860 
addPicture(const SkPicture * picture)861 void SkPictureRecord::addPicture(const SkPicture* picture) {
862     // follow the convention of recording a 1-based index
863     this->addInt(find_or_append(fPictures, picture) + 1);
864 }
865 
addDrawable(SkDrawable * drawable)866 void SkPictureRecord::addDrawable(SkDrawable* drawable) {
867     // follow the convention of recording a 1-based index
868     this->addInt(find_or_append(fDrawables, drawable) + 1);
869 }
870 
addPoint(const SkPoint & point)871 void SkPictureRecord::addPoint(const SkPoint& point) {
872     fWriter.writePoint(point);
873 }
874 
addPoints(const SkPoint pts[],int count)875 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
876     fWriter.writeMul4(pts, count * sizeof(SkPoint));
877 }
878 
addNoOp()879 void SkPictureRecord::addNoOp() {
880     size_t size = kUInt32Size; // op
881     this->addDraw(NOOP, &size);
882 }
883 
addRect(const SkRect & rect)884 void SkPictureRecord::addRect(const SkRect& rect) {
885     fWriter.writeRect(rect);
886 }
887 
addRectPtr(const SkRect * rect)888 void SkPictureRecord::addRectPtr(const SkRect* rect) {
889     if (fWriter.writeBool(rect != nullptr)) {
890         fWriter.writeRect(*rect);
891     }
892 }
893 
addIRect(const SkIRect & rect)894 void SkPictureRecord::addIRect(const SkIRect& rect) {
895     fWriter.write(&rect, sizeof(rect));
896 }
897 
addIRectPtr(const SkIRect * rect)898 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
899     if (fWriter.writeBool(rect != nullptr)) {
900         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
901     }
902 }
903 
addRRect(const SkRRect & rrect)904 void SkPictureRecord::addRRect(const SkRRect& rrect) {
905     fWriter.writeRRect(rrect);
906 }
907 
addRegion(const SkRegion & region)908 void SkPictureRecord::addRegion(const SkRegion& region) {
909     fWriter.writeRegion(region);
910 }
911 
addText(const void * text,size_t byteLength)912 void SkPictureRecord::addText(const void* text, size_t byteLength) {
913     addInt(SkToInt(byteLength));
914     fWriter.writePad(text, byteLength);
915 }
916 
addTextBlob(const SkTextBlob * blob)917 void SkPictureRecord::addTextBlob(const SkTextBlob* blob) {
918     // follow the convention of recording a 1-based index
919     this->addInt(find_or_append(fTextBlobs, blob) + 1);
920 }
921 
addVertices(const SkVertices * vertices)922 void SkPictureRecord::addVertices(const SkVertices* vertices) {
923     // follow the convention of recording a 1-based index
924     this->addInt(find_or_append(fVertices, vertices) + 1);
925 }
926 
927 ///////////////////////////////////////////////////////////////////////////////
928