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