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