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