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