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