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