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