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