• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&copy);
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