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