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