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