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