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