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