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