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