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