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