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