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 "SkPictureRecord.h"
9
10 #include "SkCanvasPriv.h"
11 #include "SkClipOpPriv.h"
12 #include "SkDrawShadowInfo.h"
13 #include "SkImage_Base.h"
14 #include "SkMatrixPriv.h"
15 #include "SkPatchUtils.h"
16 #include "SkRRect.h"
17 #include "SkRSXform.h"
18 #include "SkTSearch.h"
19 #include "SkTextBlob.h"
20 #include "SkTo.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
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)425 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
426 const SkPaint& paint) {
427 // op + paint index + mode + count + point data
428 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
429 size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
430 this->addPaint(paint);
431
432 this->addInt(mode);
433 this->addInt(SkToInt(count));
434 fWriter.writeMul4(pts, count * sizeof(SkPoint));
435 this->validate(initialOffset, size);
436 }
437
onDrawOval(const SkRect & oval,const SkPaint & paint)438 void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
439 // op + paint index + rect
440 size_t size = 2 * kUInt32Size + sizeof(oval);
441 size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
442 this->addPaint(paint);
443 this->addRect(oval);
444 this->validate(initialOffset, size);
445 }
446
onDrawArc(const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const SkPaint & paint)447 void SkPictureRecord::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
448 bool useCenter, const SkPaint& paint) {
449 // op + paint index + rect + start + sweep + bool (as int)
450 size_t size = 2 * kUInt32Size + sizeof(oval) + sizeof(startAngle) + sizeof(sweepAngle) +
451 sizeof(int);
452 size_t initialOffset = this->addDraw(DRAW_ARC, &size);
453 this->addPaint(paint);
454 this->addRect(oval);
455 this->addScalar(startAngle);
456 this->addScalar(sweepAngle);
457 this->addInt(useCenter);
458 this->validate(initialOffset, size);
459 }
460
onDrawRect(const SkRect & rect,const SkPaint & paint)461 void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
462 // op + paint index + rect
463 size_t size = 2 * kUInt32Size + sizeof(rect);
464 size_t initialOffset = this->addDraw(DRAW_RECT, &size);
465 this->addPaint(paint);
466 this->addRect(rect);
467 this->validate(initialOffset, size);
468 }
469
onDrawEdgeAARect(const SkRect & rect,SkCanvas::QuadAAFlags aa,SkColor color,SkBlendMode mode)470 void SkPictureRecord::onDrawEdgeAARect(const SkRect& rect, SkCanvas::QuadAAFlags aa,
471 SkColor color, SkBlendMode mode) {
472 // op + rect + aa flags + color + mode
473 size_t size = 4 * kUInt32Size + sizeof(rect);
474 size_t initialOffset = this->addDraw(DRAW_EDGEAA_RECT, &size);
475 this->addRect(rect);
476 this->addInt((int) aa);
477 this->addInt((int) color);
478 this->addInt((int) mode);
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
onDrawImageSet(const SkCanvas::ImageSetEntry set[],int count,SkFilterQuality filterQuality,SkBlendMode mode)577 void SkPictureRecord::onDrawImageSet(const SkCanvas::ImageSetEntry set[], int count,
578 SkFilterQuality filterQuality, SkBlendMode mode) {
579 // op + count + alpha + fq + mode + (image index, src rect, dst rect, alpha, aa flags) * cnt
580 size_t size =
581 4 * kUInt32Size + (2 * kUInt32Size + 2 * sizeof(SkRect) + sizeof(SkScalar)) * count;
582 size_t initialOffset = this->addDraw(DRAW_IMAGE_SET, &size);
583 this->addInt(count);
584 this->addInt((int)filterQuality);
585 this->addInt((int)mode);
586 for (int i = 0; i < count; ++i) {
587 this->addImage(set[i].fImage.get());
588 this->addRect(set[i].fSrcRect);
589 this->addRect(set[i].fDstRect);
590 this->addScalar(set[i].fAlpha);
591 this->addInt((int)set[i].fAAFlags);
592 }
593 this->validate(initialOffset, size);
594 }
595
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)596 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
597 const SkPaint& paint) {
598
599 // op + paint index + blob index + x/y
600 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
601 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
602
603 this->addPaint(paint);
604 this->addTextBlob(blob);
605 this->addScalar(x);
606 this->addScalar(y);
607
608 this->validate(initialOffset, size);
609 }
610
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)611 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
612 const SkPaint* paint) {
613 // op + picture index
614 size_t size = 2 * kUInt32Size;
615 size_t initialOffset;
616
617 if (nullptr == matrix && nullptr == paint) {
618 initialOffset = this->addDraw(DRAW_PICTURE, &size);
619 this->addPicture(picture);
620 } else {
621 const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
622 size += SkMatrixPriv::WriteToMemory(m, nullptr) + kUInt32Size; // matrix + paint
623 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
624 this->addPaintPtr(paint);
625 this->addMatrix(m);
626 this->addPicture(picture);
627 }
628 this->validate(initialOffset, size);
629 }
630
onDrawDrawable(SkDrawable * drawable,const SkMatrix * matrix)631 void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
632 // op + drawable index
633 size_t size = 2 * kUInt32Size;
634 size_t initialOffset;
635
636 if (nullptr == matrix) {
637 initialOffset = this->addDraw(DRAW_DRAWABLE, &size);
638 this->addDrawable(drawable);
639 } else {
640 size += SkMatrixPriv::WriteToMemory(*matrix, nullptr); // matrix
641 initialOffset = this->addDraw(DRAW_DRAWABLE_MATRIX, &size);
642 this->addMatrix(*matrix);
643 this->addDrawable(drawable);
644 }
645 this->validate(initialOffset, size);
646 }
647
onDrawVerticesObject(const SkVertices * vertices,const SkVertices::Bone bones[],int boneCount,SkBlendMode mode,const SkPaint & paint)648 void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices,
649 const SkVertices::Bone bones[], int boneCount,
650 SkBlendMode mode, const SkPaint& paint) {
651 // op + paint index + vertices index + number of bones + bone matrices + mode
652 size_t size = 5 * kUInt32Size + boneCount * sizeof(SkVertices::Bone);
653 size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size);
654
655 this->addPaint(paint);
656 this->addVertices(vertices);
657 this->addInt(boneCount);
658 fWriter.write(bones, boneCount * sizeof(SkVertices::Bone));
659 this->addInt(static_cast<uint32_t>(mode));
660
661 this->validate(initialOffset, size);
662 }
663
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkBlendMode bmode,const SkPaint & paint)664 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
665 const SkPoint texCoords[4], SkBlendMode bmode,
666 const SkPaint& paint) {
667 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
668 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
669 uint32_t flag = 0;
670 if (colors) {
671 flag |= DRAW_VERTICES_HAS_COLORS;
672 size += SkPatchUtils::kNumCorners * sizeof(SkColor);
673 }
674 if (texCoords) {
675 flag |= DRAW_VERTICES_HAS_TEXS;
676 size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
677 }
678 if (SkBlendMode::kModulate != bmode) {
679 flag |= DRAW_VERTICES_HAS_XFER;
680 size += kUInt32Size;
681 }
682
683 size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
684 this->addPaint(paint);
685 this->addPatch(cubics);
686 this->addInt(flag);
687
688 // write optional parameters
689 if (colors) {
690 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
691 }
692 if (texCoords) {
693 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
694 }
695 if (flag & DRAW_VERTICES_HAS_XFER) {
696 this->addInt((int)bmode);
697 }
698 this->validate(initialOffset, size);
699 }
700
onDrawAtlas(const SkImage * atlas,const SkRSXform xform[],const SkRect tex[],const SkColor colors[],int count,SkBlendMode mode,const SkRect * cull,const SkPaint * paint)701 void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
702 const SkColor colors[], int count, SkBlendMode mode,
703 const SkRect* cull, const SkPaint* paint) {
704 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
705 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
706 uint32_t flags = 0;
707 if (colors) {
708 flags |= DRAW_ATLAS_HAS_COLORS;
709 size += count * sizeof(SkColor);
710 size += sizeof(uint32_t); // xfermode::mode
711 }
712 if (cull) {
713 flags |= DRAW_ATLAS_HAS_CULL;
714 size += sizeof(SkRect);
715 }
716
717 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
718 this->addPaintPtr(paint);
719 this->addImage(atlas);
720 this->addInt(flags);
721 this->addInt(count);
722 fWriter.write(xform, count * sizeof(SkRSXform));
723 fWriter.write(tex, count * sizeof(SkRect));
724
725 // write optional parameters
726 if (colors) {
727 fWriter.write(colors, count * sizeof(SkColor));
728 this->addInt((int)mode);
729 }
730 if (cull) {
731 fWriter.write(cull, sizeof(SkRect));
732 }
733 this->validate(initialOffset, size);
734 }
735
onDrawShadowRec(const SkPath & path,const SkDrawShadowRec & rec)736 void SkPictureRecord::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
737 // op + path index + zParams + lightPos + lightRadius + spot/ambient alphas + color + flags
738 size_t size = 2 * kUInt32Size + 2 * sizeof(SkPoint3) + 1 * sizeof(SkScalar) + 3 * kUInt32Size;
739 size_t initialOffset = this->addDraw(DRAW_SHADOW_REC, &size);
740
741 this->addPath(path);
742
743 fWriter.writePoint3(rec.fZPlaneParams);
744 fWriter.writePoint3(rec.fLightPos);
745 fWriter.writeScalar(rec.fLightRadius);
746 fWriter.write32(rec.fAmbientColor);
747 fWriter.write32(rec.fSpotColor);
748 fWriter.write32(rec.fFlags);
749
750 this->validate(initialOffset, size);
751 }
752
onDrawAnnotation(const SkRect & rect,const char key[],SkData * value)753 void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
754 size_t keyLen = fWriter.WriteStringSize(key);
755 size_t valueLen = fWriter.WriteDataSize(value);
756 size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
757
758 size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
759 this->addRect(rect);
760 fWriter.writeString(key);
761 fWriter.writeData(value);
762 this->validate(initialOffset, size);
763 }
764
765 ///////////////////////////////////////////////////////////////////////////////
766
767 // De-duping helper.
768
769 template <typename T>
equals(T * a,T * b)770 static bool equals(T* a, T* b) { return a->uniqueID() == b->uniqueID(); }
771
772 template <>
equals(SkDrawable * a,SkDrawable * b)773 bool equals(SkDrawable* a, SkDrawable* b) {
774 // SkDrawable's generationID is not a stable unique identifier.
775 return a == b;
776 }
777
778 template <typename T>
find_or_append(SkTArray<sk_sp<T>> & array,T * obj)779 static int find_or_append(SkTArray<sk_sp<T>>& array, T* obj) {
780 for (int i = 0; i < array.count(); i++) {
781 if (equals(array[i].get(), obj)) {
782 return i;
783 }
784 }
785
786 array.push_back(sk_ref_sp(obj));
787
788 return array.count() - 1;
789 }
790
onNewSurface(const SkImageInfo & info,const SkSurfaceProps &)791 sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
792 return nullptr;
793 }
794
addImage(const SkImage * image)795 void SkPictureRecord::addImage(const SkImage* image) {
796 // convention for images is 0-based index
797 this->addInt(find_or_append(fImages, image));
798 }
799
addMatrix(const SkMatrix & matrix)800 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
801 fWriter.writeMatrix(matrix);
802 }
803
addPaintPtr(const SkPaint * paint)804 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
805 if (paint) {
806 fPaints.push_back(*paint);
807 this->addInt(fPaints.count());
808 } else {
809 this->addInt(0);
810 }
811 }
812
addPathToHeap(const SkPath & path)813 int SkPictureRecord::addPathToHeap(const SkPath& path) {
814 if (int* n = fPaths.find(path)) {
815 return *n;
816 }
817 int n = fPaths.count() + 1; // 0 is reserved for null / error.
818 fPaths.set(path, n);
819 return n;
820 }
821
addPath(const SkPath & path)822 void SkPictureRecord::addPath(const SkPath& path) {
823 this->addInt(this->addPathToHeap(path));
824 }
825
addPatch(const SkPoint cubics[12])826 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
827 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
828 }
829
addPicture(const SkPicture * picture)830 void SkPictureRecord::addPicture(const SkPicture* picture) {
831 // follow the convention of recording a 1-based index
832 this->addInt(find_or_append(fPictures, picture) + 1);
833 }
834
addDrawable(SkDrawable * drawable)835 void SkPictureRecord::addDrawable(SkDrawable* drawable) {
836 // follow the convention of recording a 1-based index
837 this->addInt(find_or_append(fDrawables, drawable) + 1);
838 }
839
addPoint(const SkPoint & point)840 void SkPictureRecord::addPoint(const SkPoint& point) {
841 fWriter.writePoint(point);
842 }
843
addPoints(const SkPoint pts[],int count)844 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
845 fWriter.writeMul4(pts, count * sizeof(SkPoint));
846 }
847
addNoOp()848 void SkPictureRecord::addNoOp() {
849 size_t size = kUInt32Size; // op
850 this->addDraw(NOOP, &size);
851 }
852
addRect(const SkRect & rect)853 void SkPictureRecord::addRect(const SkRect& rect) {
854 fWriter.writeRect(rect);
855 }
856
addRectPtr(const SkRect * rect)857 void SkPictureRecord::addRectPtr(const SkRect* rect) {
858 if (fWriter.writeBool(rect != nullptr)) {
859 fWriter.writeRect(*rect);
860 }
861 }
862
addIRect(const SkIRect & rect)863 void SkPictureRecord::addIRect(const SkIRect& rect) {
864 fWriter.write(&rect, sizeof(rect));
865 }
866
addIRectPtr(const SkIRect * rect)867 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
868 if (fWriter.writeBool(rect != nullptr)) {
869 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
870 }
871 }
872
addRRect(const SkRRect & rrect)873 void SkPictureRecord::addRRect(const SkRRect& rrect) {
874 fWriter.writeRRect(rrect);
875 }
876
addRegion(const SkRegion & region)877 void SkPictureRecord::addRegion(const SkRegion& region) {
878 fWriter.writeRegion(region);
879 }
880
addText(const void * text,size_t byteLength)881 void SkPictureRecord::addText(const void* text, size_t byteLength) {
882 addInt(SkToInt(byteLength));
883 fWriter.writePad(text, byteLength);
884 }
885
addTextBlob(const SkTextBlob * blob)886 void SkPictureRecord::addTextBlob(const SkTextBlob* blob) {
887 // follow the convention of recording a 1-based index
888 this->addInt(find_or_append(fTextBlobs, blob) + 1);
889 }
890
addVertices(const SkVertices * vertices)891 void SkPictureRecord::addVertices(const SkVertices* vertices) {
892 // follow the convention of recording a 1-based index
893 this->addInt(find_or_append(fVertices, vertices) + 1);
894 }
895
896 ///////////////////////////////////////////////////////////////////////////////
897