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