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