• 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