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