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