• 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 "SkTSearch.h"
10 #include "SkPixelRef.h"
11 #include "SkRRect.h"
12 #include "SkBBoxHierarchy.h"
13 #include "SkDevice.h"
14 #include "SkPictureStateTree.h"
15 
16 #define HEAP_BLOCK_SIZE 4096
17 
18 // If SK_RECORD_LITERAL_PICTURES is defined, record our inputs as literally as possible.
19 // Otherwise, we can be clever and record faster equivalents.  kBeClever is normally true.
20 static const bool kBeClever =
21 #ifdef SK_RECORD_LITERAL_PICTURES
22     false;
23 #else
24     true;
25 #endif
26 
27 enum {
28     // just need a value that save or getSaveCount would never return
29     kNoInitialSave = -1,
30 };
31 
32 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
33 static int const kUInt32Size = 4;
34 
35 static const uint32_t kSaveSize = 2 * kUInt32Size;
36 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
37 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
38 
SkPictureRecord(const SkISize & dimensions,uint32_t flags)39 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
40     : INHERITED(dimensions.width(), dimensions.height())
41     , fBoundingHierarchy(NULL)
42     , fStateTree(NULL)
43     , fFlattenableHeap(HEAP_BLOCK_SIZE)
44     , fPaints(&fFlattenableHeap)
45     , fRecordFlags(flags)
46     , fOptsEnabled(kBeClever) {
47 #ifdef SK_DEBUG_SIZE
48     fPointBytes = fRectBytes = fTextBytes = 0;
49     fPointWrites = fRectWrites = fTextWrites = 0;
50 #endif
51 
52     fBitmapHeap = SkNEW(SkBitmapHeap);
53     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
54 
55 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
56     fFirstSavedLayerIndex = kNoSavedLayerIndex;
57 #endif
58 
59     fInitialSaveCount = kNoInitialSave;
60 
61 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
62     fMCMgr.init(this);
63 #endif
64 }
65 
~SkPictureRecord()66 SkPictureRecord::~SkPictureRecord() {
67     SkSafeUnref(fBitmapHeap);
68     SkSafeUnref(fBoundingHierarchy);
69     SkSafeUnref(fStateTree);
70     fFlattenableHeap.setBitmapStorage(NULL);
71     fPictureRefs.unrefAll();
72 }
73 
74 ///////////////////////////////////////////////////////////////////////////////
75 
76 // Return the offset of the paint inside a given op's byte stream. A zero
77 // return value means there is no paint (and you really shouldn't be calling
78 // this method)
getPaintOffset(DrawType op,size_t opSize)79 static inline size_t getPaintOffset(DrawType op, size_t opSize) {
80     // These offsets are where the paint would be if the op size doesn't overflow
81     static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
82         0,  // UNUSED - no paint
83         0,  // CLIP_PATH - no paint
84         0,  // CLIP_REGION - no paint
85         0,  // CLIP_RECT - no paint
86         0,  // CLIP_RRECT - no paint
87         0,  // CONCAT - no paint
88         1,  // DRAW_BITMAP - right after op code
89         1,  // DRAW_BITMAP_MATRIX - right after op code
90         1,  // DRAW_BITMAP_NINE - right after op code
91         1,  // DRAW_BITMAP_RECT_TO_RECT - right after op code
92         0,  // DRAW_CLEAR - no paint
93         0,  // DRAW_DATA - no paint
94         1,  // DRAW_OVAL - right after op code
95         1,  // DRAW_PAINT - right after op code
96         1,  // DRAW_PATH - right after op code
97         0,  // DRAW_PICTURE - no paint
98         1,  // DRAW_POINTS - right after op code
99         1,  // DRAW_POS_TEXT - right after op code
100         1,  // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
101         1,  // DRAW_POS_TEXT_H - right after op code
102         1,  // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
103         1,  // DRAW_RECT - right after op code
104         1,  // DRAW_RRECT - right after op code
105         1,  // DRAW_SPRITE - right after op code
106         1,  // DRAW_TEXT - right after op code
107         1,  // DRAW_TEXT_ON_PATH - right after op code
108         1,  // DRAW_TEXT_TOP_BOTTOM - right after op code
109         1,  // DRAW_VERTICES - right after op code
110         0,  // RESTORE - no paint
111         0,  // ROTATE - no paint
112         0,  // SAVE - no paint
113         0,  // SAVE_LAYER - see below - this paint's location varies
114         0,  // SCALE - no paint
115         0,  // SET_MATRIX - no paint
116         0,  // SKEW - no paint
117         0,  // TRANSLATE - no paint
118         0,  // NOOP - no paint
119         0,  // BEGIN_GROUP - no paint
120         0,  // COMMENT - no paint
121         0,  // END_GROUP - no paint
122         1,  // DRAWDRRECT - right after op code
123         0,  // PUSH_CULL - no paint
124         0,  // POP_CULL - no paint
125     };
126 
127     SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
128                       need_to_be_in_sync);
129     SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
130 
131     int overflow = 0;
132     if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
133         // This op's size overflows so an extra uint32_t will be written
134         // after the op code
135         overflow = sizeof(uint32_t);
136     }
137 
138     if (SAVE_LAYER == op) {
139         static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
140         static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
141 
142         if (kSaveLayerNoBoundsSize == opSize) {
143             return kSaveLayerNoBoundsPaintOffset + overflow;
144         } else {
145             SkASSERT(kSaveLayerWithBoundsSize == opSize);
146             return kSaveLayerWithBoundsPaintOffset + overflow;
147         }
148     }
149 
150     SkASSERT(0 != gPaintOffsets[op]);   // really shouldn't be calling this method
151     return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
152 }
153 
willSave(SaveFlags flags)154 void SkPictureRecord::willSave(SaveFlags flags) {
155 
156 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
157     fMCMgr.save(flags);
158 #else
159     // record the offset to us, making it non-positive to distinguish a save
160     // from a clip entry.
161     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
162     this->recordSave(flags);
163 #endif
164 
165     this->INHERITED::willSave(flags);
166 }
167 
recordSave(SaveFlags flags)168 void SkPictureRecord::recordSave(SaveFlags flags) {
169     // op + flags
170     size_t size = kSaveSize;
171     size_t initialOffset = this->addDraw(SAVE, &size);
172     this->addInt(flags);
173 
174     this->validate(initialOffset, size);
175 }
176 
willSaveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)177 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
178                                                            const SkPaint* paint, SaveFlags flags) {
179 
180 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
181     fMCMgr.saveLayer(bounds, paint, flags);
182 #else
183     // record the offset to us, making it non-positive to distinguish a save
184     // from a clip entry.
185     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
186     this->recordSaveLayer(bounds, paint, flags);
187     if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
188         fFirstSavedLayerIndex = fRestoreOffsetStack.count();
189     }
190 #endif
191 
192     this->INHERITED::willSaveLayer(bounds, paint, flags);
193     /*  No need for a (potentially very big) layer which we don't actually need
194         at this time (and may not be able to afford since during record our
195         clip starts out the size of the picture, which is often much larger
196         than the size of the actual device we'll use during playback).
197      */
198     return kNoLayer_SaveLayerStrategy;
199 }
200 
recordSaveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)201 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
202                                       SaveFlags flags) {
203     // op + bool for 'bounds'
204     size_t size = 2 * kUInt32Size;
205     if (NULL != bounds) {
206         size += sizeof(*bounds); // + rect
207     }
208     // + paint index + flags
209     size += 2 * kUInt32Size;
210 
211     SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
212 
213     size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
214     this->addRectPtr(bounds);
215     SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
216     this->addPaintPtr(paint);
217     this->addInt(flags);
218 
219     this->validate(initialOffset, size);
220 }
221 
isDrawingToLayer() const222 bool SkPictureRecord::isDrawingToLayer() const {
223 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
224     return fMCMgr.isDrawingToLayer();
225 #else
226     return fFirstSavedLayerIndex != kNoSavedLayerIndex;
227 #endif
228 }
229 
230 /*
231  * Read the op code from 'offset' in 'writer'.
232  */
233 #ifdef SK_DEBUG
peek_op(SkWriter32 * writer,size_t offset)234 static DrawType peek_op(SkWriter32* writer, size_t offset) {
235     return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
236 }
237 #endif
238 
239 /*
240  * Read the op code from 'offset' in 'writer' and extract the size too.
241  */
peek_op_and_size(SkWriter32 * writer,size_t offset,uint32_t * size)242 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
243     uint32_t peek = writer->readTAt<uint32_t>(offset);
244 
245     uint32_t op;
246     UNPACK_8_24(peek, op, *size);
247     if (MASK_24 == *size) {
248         // size required its own slot right after the op code
249         *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
250     }
251     return (DrawType) op;
252 }
253 
254 #ifdef TRACK_COLLAPSE_STATS
255     static int gCollapseCount, gCollapseCalls;
256 #endif
257 
258 // Is the supplied paint simply a color?
is_simple(const SkPaint & p)259 static bool is_simple(const SkPaint& p) {
260     intptr_t orAccum = (intptr_t)p.getPathEffect()  |
261                        (intptr_t)p.getShader()      |
262                        (intptr_t)p.getXfermode()    |
263                        (intptr_t)p.getMaskFilter()  |
264                        (intptr_t)p.getColorFilter() |
265                        (intptr_t)p.getRasterizer()  |
266                        (intptr_t)p.getLooper()      |
267                        (intptr_t)p.getImageFilter();
268     return 0 == orAccum;
269 }
270 
271 // CommandInfos are fed to the 'match' method and filled in with command
272 // information.
273 struct CommandInfo {
274     DrawType fActualOp;
275     uint32_t fOffset;
276     uint32_t fSize;
277 };
278 
279 /*
280  * Attempt to match the provided pattern of commands starting at 'offset'
281  * in the byte stream and stopping at the end of the stream. Upon success,
282  * return true with all the pattern information filled out in the result
283  * array (i.e., actual ops, offsets and sizes).
284  * Note this method skips any NOOPs seen in the stream
285  */
match(SkWriter32 * writer,uint32_t offset,int * pattern,CommandInfo * result,int numCommands)286 static bool match(SkWriter32* writer, uint32_t offset,
287                   int* pattern, CommandInfo* result, int numCommands) {
288     SkASSERT(offset < writer->bytesWritten());
289 
290     uint32_t curOffset = offset;
291     uint32_t curSize = 0;
292     int numMatched;
293     for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
294         DrawType op = peek_op_and_size(writer, curOffset, &curSize);
295         while (NOOP == op) {
296             curOffset += curSize;
297             if (curOffset >= writer->bytesWritten()) {
298                 return false;
299             }
300             op = peek_op_and_size(writer, curOffset, &curSize);
301         }
302 
303         if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
304             if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
305                 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
306                 return false;
307             }
308         } else if (op != pattern[numMatched]) {
309             return false;
310         }
311 
312         result[numMatched].fActualOp = op;
313         result[numMatched].fOffset = curOffset;
314         result[numMatched].fSize = curSize;
315 
316         curOffset += curSize;
317     }
318 
319     if (numMatched != numCommands) {
320         return false;
321     }
322 
323     curOffset += curSize;
324     if (curOffset < writer->bytesWritten()) {
325         // Something else between the last command and the end of the stream
326         return false;
327     }
328 
329     return true;
330 }
331 
332 // temporarily here to make code review easier
333 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
334                                                  SkPaintDictionary* paintDict,
335                                                  const CommandInfo& saveLayerInfo,
336                                                  const CommandInfo& dbmInfo);
337 
338 /*
339  * Restore has just been called (but not recorded), look back at the
340  * matching save* and see if we are in the configuration:
341  *   SAVE_LAYER
342  *       DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
343  *   RESTORE
344  * where the saveLayer's color can be moved into the drawBitmap*'s paint
345  */
remove_save_layer1(SkWriter32 * writer,int32_t offset,SkPaintDictionary * paintDict)346 static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
347                                SkPaintDictionary* paintDict) {
348     // back up to the save block
349     // TODO: add a stack to track save*/restore offsets rather than searching backwards
350     while (offset > 0) {
351         offset = writer->readTAt<uint32_t>(offset);
352     }
353 
354     int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
355     CommandInfo result[SK_ARRAY_COUNT(pattern)];
356 
357     if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
358         return false;
359     }
360 
361     if (kSaveLayerWithBoundsSize == result[0].fSize) {
362         // The saveLayer's bound can offset where the dbm is drawn
363         return false;
364     }
365 
366     return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
367                                                 result[0], result[1]);
368 }
369 
370 /*
371  * Convert the command code located at 'offset' to a NOOP. Leave the size
372  * field alone so the NOOP can be skipped later.
373  */
convert_command_to_noop(SkWriter32 * writer,uint32_t offset)374 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
375     uint32_t command = writer->readTAt<uint32_t>(offset);
376     writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
377 }
378 
379 /*
380  * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
381  * Return true on success; false otherwise.
382  */
merge_savelayer_paint_into_drawbitmp(SkWriter32 * writer,SkPaintDictionary * paintDict,const CommandInfo & saveLayerInfo,const CommandInfo & dbmInfo)383 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
384                                                  SkPaintDictionary* paintDict,
385                                                  const CommandInfo& saveLayerInfo,
386                                                  const CommandInfo& dbmInfo) {
387     SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
388     SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
389              DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
390              DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
391              DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
392 
393     size_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
394     size_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
395 
396     // we have a match, now we need to get the paints involved
397     uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
398     uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
399 
400     if (0 == saveLayerPaintId) {
401         // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
402         // and signal the caller (by returning true) to not add the RESTORE op
403         convert_command_to_noop(writer, saveLayerInfo.fOffset);
404         return true;
405     }
406 
407     if (0 == dbmPaintId) {
408         // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
409         // and signal the caller (by returning true) to not add the RESTORE op
410         convert_command_to_noop(writer, saveLayerInfo.fOffset);
411         writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
412         return true;
413     }
414 
415     SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
416     if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
417         return false;
418     }
419 
420     // For this optimization we only fold the saveLayer and drawBitmapRect
421     // together if the saveLayer's draw is simple (i.e., no fancy effects) and
422     // and the only difference in the colors is that the saveLayer's can have
423     // an alpha while the drawBitmapRect's is opaque.
424     // TODO: it should be possible to fold them together even if they both
425     // have different non-255 alphas
426     SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
427 
428     SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
429     if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor || !is_simple(*dbmPaint)) {
430         return false;
431     }
432 
433     SkColor newColor = SkColorSetA(dbmPaint->getColor(),
434                                    SkColorGetA(saveLayerPaint->getColor()));
435     dbmPaint->setColor(newColor);
436 
437     const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
438     if (NULL == data) {
439         return false;
440     }
441 
442     // kill the saveLayer and alter the DBMR2R's paint to be the modified one
443     convert_command_to_noop(writer, saveLayerInfo.fOffset);
444     writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
445     return true;
446 }
447 
448 /*
449  * Restore has just been called (but not recorded), look back at the
450  * matching save* and see if we are in the configuration:
451  *   SAVE_LAYER (with NULL == bounds)
452  *      SAVE
453  *         CLIP_RECT
454  *         DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
455  *      RESTORE
456  *   RESTORE
457  * where the saveLayer's color can be moved into the drawBitmap*'s paint
458  */
remove_save_layer2(SkWriter32 * writer,int32_t offset,SkPaintDictionary * paintDict)459 static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
460                                SkPaintDictionary* paintDict) {
461 
462     // back up to the save block
463     // TODO: add a stack to track save*/restore offsets rather than searching backwards
464     while (offset > 0) {
465         offset = writer->readTAt<uint32_t>(offset);
466     }
467 
468     int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
469     CommandInfo result[SK_ARRAY_COUNT(pattern)];
470 
471     if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
472         return false;
473     }
474 
475     if (kSaveLayerWithBoundsSize == result[0].fSize) {
476         // The saveLayer's bound can offset where the dbm is drawn
477         return false;
478     }
479 
480     return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
481                                                 result[0], result[3]);
482 }
483 
is_drawing_op(DrawType op)484 static bool is_drawing_op(DrawType op) {
485     return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
486 }
487 
488 /*
489  *  Restore has just been called (but not recorded), so look back at the
490  *  matching save(), and see if we can eliminate the pair of them, due to no
491  *  intervening matrix/clip calls.
492  *
493  *  If so, update the writer and return true, in which case we won't even record
494  *  the restore() call. If we still need the restore(), return false.
495  */
collapse_save_clip_restore(SkWriter32 * writer,int32_t offset,SkPaintDictionary * paintDict)496 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
497                                        SkPaintDictionary* paintDict) {
498 #ifdef TRACK_COLLAPSE_STATS
499     gCollapseCalls += 1;
500 #endif
501 
502     int32_t restoreOffset = (int32_t)writer->bytesWritten();
503 
504     // back up to the save block
505     while (offset > 0) {
506         offset = writer->readTAt<uint32_t>(offset);
507     }
508 
509     // now offset points to a save
510     offset = -offset;
511     uint32_t opSize;
512     DrawType op = peek_op_and_size(writer, offset, &opSize);
513     if (SAVE_LAYER == op) {
514         // not ready to cull these out yet (mrr)
515         return false;
516     }
517     SkASSERT(SAVE == op);
518     SkASSERT(kSaveSize == opSize);
519 
520     // get the save flag (last 4-bytes of the space allocated for the opSize)
521     SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
522     if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
523         // This function's optimization is only correct for kMatrixClip style saves.
524         // TODO: set checkMatrix & checkClip booleans here and then check for the
525         // offending operations in the following loop.
526         return false;
527     }
528 
529     // Walk forward until we get back to either a draw-verb (abort) or we hit
530     // our restore (success).
531     int32_t saveOffset = offset;
532 
533     offset += opSize;
534     while (offset < restoreOffset) {
535         op = peek_op_and_size(writer, offset, &opSize);
536         if (is_drawing_op(op) || (SAVE_LAYER == op)) {
537             // drawing verb, abort
538             return false;
539         }
540         offset += opSize;
541     }
542 
543 #ifdef TRACK_COLLAPSE_STATS
544     gCollapseCount += 1;
545     SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
546              (double)gCollapseCount / gCollapseCalls, "%");
547 #endif
548 
549     writer->rewindToOffset(saveOffset);
550     return true;
551 }
552 
553 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
554                                      SkPaintDictionary* paintDict);
555 enum PictureRecordOptType {
556     kRewind_OptType,  // Optimization rewinds the command stream
557     kCollapseSaveLayer_OptType,  // Optimization eliminates a save/restore pair
558 };
559 
560 enum PictureRecordOptFlags {
561     kSkipIfBBoxHierarchy_Flag = 0x1,  // Optimization should be skipped if the
562                                       // SkPicture has a bounding box hierarchy.
563 };
564 
565 struct PictureRecordOpt {
566     PictureRecordOptProc fProc;
567     PictureRecordOptType fType;
568     unsigned fFlags;
569 };
570 /*
571  * A list of the optimizations that are tried upon seeing a restore
572  * TODO: add a real API for such optimizations
573  *       Add the ability to fire optimizations on any op (not just RESTORE)
574  */
575 static const PictureRecordOpt gPictureRecordOpts[] = {
576     // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
577     // because it is redundant with the state traversal optimization in
578     // SkPictureStateTree, and applying the optimization introduces significant
579     // record time overhead because it requires rewinding contents that were
580     // recorded into the BBoxHierarchy.
581     { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
582     { remove_save_layer1,         kCollapseSaveLayer_OptType, 0 },
583     { remove_save_layer2,         kCollapseSaveLayer_OptType, 0 }
584 };
585 
586 // This is called after an optimization has been applied to the command stream
587 // in order to adjust the contents and state of the bounding box hierarchy and
588 // state tree to reflect the optimization.
apply_optimization_to_bbh(PictureRecordOptType opt,SkPictureStateTree * stateTree,SkBBoxHierarchy * boundingHierarchy)589 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
590                                       SkBBoxHierarchy* boundingHierarchy) {
591     switch (opt) {
592     case kCollapseSaveLayer_OptType:
593         if (NULL != stateTree) {
594             stateTree->saveCollapsed();
595         }
596         break;
597     case kRewind_OptType:
598         if (NULL != boundingHierarchy) {
599             boundingHierarchy->rewindInserts();
600         }
601         // Note: No need to touch the state tree for this to work correctly.
602         // Unused branches do not burden the playback, and pruning the tree
603         // would be O(N^2), so it is best to leave it alone.
604         break;
605     default:
606         SkASSERT(0);
607     }
608 }
609 
willRestore()610 void SkPictureRecord::willRestore() {
611     // FIXME: SkDeferredCanvas needs to be refactored to respect
612     // save/restore balancing so that the following test can be
613     // turned on permanently.
614 #if 0
615     SkASSERT(fRestoreOffsetStack.count() > 1);
616 #endif
617 
618 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
619     if (fMCMgr.getSaveCount() == 1) {
620         return;
621     }
622 
623     fMCMgr.restore();
624 #else
625     // check for underflow
626     if (fRestoreOffsetStack.count() == 0) {
627         return;
628     }
629 
630     if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
631         fFirstSavedLayerIndex = kNoSavedLayerIndex;
632     }
633 
634     size_t opt = 0;
635     if (fOptsEnabled) {
636         for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
637             if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
638                 && NULL != fBoundingHierarchy) {
639                 continue;
640             }
641             if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
642                 // Some optimization fired so don't add the RESTORE
643                 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
644                                           fStateTree, fBoundingHierarchy);
645                 break;
646             }
647         }
648     }
649 
650     if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
651         // No optimization fired so add the RESTORE
652         this->recordRestore();
653     }
654 
655     fRestoreOffsetStack.pop();
656 #endif
657 
658     this->INHERITED::willRestore();
659 }
660 
recordRestore(bool fillInSkips)661 void SkPictureRecord::recordRestore(bool fillInSkips) {
662     if (fillInSkips) {
663         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
664     }
665     size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
666     size_t initialOffset = this->addDraw(RESTORE, &size);
667     this->validate(initialOffset, size);
668 }
669 
recordTranslate(const SkMatrix & m)670 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
671     SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
672 
673     // op + dx + dy
674     size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
675     size_t initialOffset = this->addDraw(TRANSLATE, &size);
676     this->addScalar(m.getTranslateX());
677     this->addScalar(m.getTranslateY());
678     this->validate(initialOffset, size);
679 }
680 
recordScale(const SkMatrix & m)681 void SkPictureRecord::recordScale(const SkMatrix& m) {
682     SkASSERT(SkMatrix::kScale_Mask == m.getType());
683 
684     // op + sx + sy
685     size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
686     size_t initialOffset = this->addDraw(SCALE, &size);
687     this->addScalar(m.getScaleX());
688     this->addScalar(m.getScaleY());
689     this->validate(initialOffset, size);
690 }
691 
didConcat(const SkMatrix & matrix)692 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
693 
694 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
695     fMCMgr.concat(matrix);
696 #else
697     switch (matrix.getType()) {
698         case SkMatrix::kTranslate_Mask:
699             this->recordTranslate(matrix);
700             break;
701         case SkMatrix::kScale_Mask:
702             this->recordScale(matrix);
703             break;
704         default:
705             this->recordConcat(matrix);
706             break;
707     }
708 #endif
709     this->INHERITED::didConcat(matrix);
710 }
711 
recordConcat(const SkMatrix & matrix)712 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
713     this->validate(fWriter.bytesWritten(), 0);
714     // op + matrix
715     size_t size = kUInt32Size + matrix.writeToMemory(NULL);
716     size_t initialOffset = this->addDraw(CONCAT, &size);
717     this->addMatrix(matrix);
718     this->validate(initialOffset, size);
719 }
720 
didSetMatrix(const SkMatrix & matrix)721 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
722 
723 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
724     fMCMgr.setMatrix(matrix);
725 #else
726     this->validate(fWriter.bytesWritten(), 0);
727     // op + matrix
728     size_t size = kUInt32Size + matrix.writeToMemory(NULL);
729     size_t initialOffset = this->addDraw(SET_MATRIX, &size);
730     this->addMatrix(matrix);
731     this->validate(initialOffset, size);
732 #endif
733     this->INHERITED::didSetMatrix(matrix);
734 }
735 
regionOpExpands(SkRegion::Op op)736 static bool regionOpExpands(SkRegion::Op op) {
737     switch (op) {
738         case SkRegion::kUnion_Op:
739         case SkRegion::kXOR_Op:
740         case SkRegion::kReverseDifference_Op:
741         case SkRegion::kReplace_Op:
742             return true;
743         case SkRegion::kIntersect_Op:
744         case SkRegion::kDifference_Op:
745             return false;
746         default:
747             SkDEBUGFAIL("unknown region op");
748             return false;
749     }
750 }
751 
752 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset)753 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
754     fMCMgr.fillInSkips(&fWriter, restoreOffset);
755 }
756 #else
fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset)757 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
758     int32_t offset = fRestoreOffsetStack.top();
759     while (offset > 0) {
760         uint32_t peek = fWriter.readTAt<uint32_t>(offset);
761         fWriter.overwriteTAt(offset, restoreOffset);
762         offset = peek;
763     }
764 
765 #ifdef SK_DEBUG
766     // assert that the final offset value points to a save verb
767     uint32_t opSize;
768     DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
769     SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
770 #endif
771 }
772 #endif
773 
beginRecording()774 void SkPictureRecord::beginRecording() {
775     // we have to call this *after* our constructor, to ensure that it gets
776     // recorded. This is balanced by restoreToCount() call from endRecording,
777     // which in-turn calls our overridden restore(), so those get recorded too.
778     fInitialSaveCount = this->save();
779 }
780 
endRecording()781 void SkPictureRecord::endRecording() {
782     SkASSERT(kNoInitialSave != fInitialSaveCount);
783     this->restoreToCount(fInitialSaveCount);
784 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
785     fMCMgr.finish();
786 #endif
787 }
788 
789 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
recordRestoreOffsetPlaceholder(SkRegion::Op op)790 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
791     size_t offset = fWriter.bytesWritten();
792     this->addInt(-1);
793     return offset;
794 }
795 #else
recordRestoreOffsetPlaceholder(SkRegion::Op op)796 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
797     if (fRestoreOffsetStack.isEmpty()) {
798         return -1;
799     }
800 
801     // The RestoreOffset field is initially filled with a placeholder
802     // value that points to the offset of the previous RestoreOffset
803     // in the current stack level, thus forming a linked list so that
804     // the restore offsets can be filled in when the corresponding
805     // restore command is recorded.
806     int32_t prevOffset = fRestoreOffsetStack.top();
807 
808     if (regionOpExpands(op)) {
809         // Run back through any previous clip ops, and mark their offset to
810         // be 0, disabling their ability to trigger a jump-to-restore, otherwise
811         // they could hide this clips ability to expand the clip (i.e. go from
812         // empty to non-empty).
813         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
814 
815         // Reset the pointer back to the previous clip so that subsequent
816         // restores don't overwrite the offsets we just cleared.
817         prevOffset = 0;
818     }
819 
820     size_t offset = fWriter.bytesWritten();
821     this->addInt(prevOffset);
822     fRestoreOffsetStack.top() = SkToU32(offset);
823     return offset;
824 }
825 #endif
826 
onClipRect(const SkRect & rect,SkRegion::Op op,ClipEdgeStyle edgeStyle)827 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
828 
829 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
830     fMCMgr.clipRect(rect, op, doAA);
831 #else
832     this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
833 #endif
834     this->INHERITED::onClipRect(rect, op, edgeStyle);
835 }
836 
recordClipRect(const SkRect & rect,SkRegion::Op op,bool doAA)837 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
838     // id + rect + clip params
839     size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
840 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
841     size += kUInt32Size;    // + restore offset
842 #else
843     // recordRestoreOffsetPlaceholder doesn't always write an offset
844     if (!fRestoreOffsetStack.isEmpty()) {
845         // + restore offset
846         size += kUInt32Size;
847     }
848 #endif
849     size_t initialOffset = this->addDraw(CLIP_RECT, &size);
850     this->addRect(rect);
851     this->addInt(ClipParams_pack(op, doAA));
852     size_t offset = this->recordRestoreOffsetPlaceholder(op);
853 
854     this->validate(initialOffset, size);
855     return offset;
856 }
857 
onClipRRect(const SkRRect & rrect,SkRegion::Op op,ClipEdgeStyle edgeStyle)858 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
859 
860 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
861     fMCMgr.clipRRect(rrect, op, doAA);
862 #else
863     this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
864 #endif
865     this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
866 }
867 
recordClipRRect(const SkRRect & rrect,SkRegion::Op op,bool doAA)868 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
869     // op + rrect + clip params
870     size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
871 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
872     size += kUInt32Size;    // + restore offset
873 #else
874     // recordRestoreOffsetPlaceholder doesn't always write an offset
875     if (!fRestoreOffsetStack.isEmpty()) {
876         // + restore offset
877         size += kUInt32Size;
878     }
879 #endif
880     size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
881     this->addRRect(rrect);
882     this->addInt(ClipParams_pack(op, doAA));
883     size_t offset = recordRestoreOffsetPlaceholder(op);
884     this->validate(initialOffset, size);
885     return offset;
886 }
887 
onClipPath(const SkPath & path,SkRegion::Op op,ClipEdgeStyle edgeStyle)888 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
889 
890 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
891     fMCMgr.clipPath(path, op, doAA);
892 #else
893     int pathID = this->addPathToHeap(path);
894     this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
895 #endif
896 
897     this->updateClipConservativelyUsingBounds(path.getBounds(), op,
898                                               path.isInverseFillType());
899 }
900 
recordClipPath(int pathID,SkRegion::Op op,bool doAA)901 size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
902     // op + path index + clip params
903     size_t size = 3 * kUInt32Size;
904 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
905     size += kUInt32Size;    // + restore offset
906 #else
907     // recordRestoreOffsetPlaceholder doesn't always write an offset
908     if (!fRestoreOffsetStack.isEmpty()) {
909         // + restore offset
910         size += kUInt32Size;
911     }
912 #endif
913     size_t initialOffset = this->addDraw(CLIP_PATH, &size);
914     this->addInt(pathID);
915     this->addInt(ClipParams_pack(op, doAA));
916     size_t offset = recordRestoreOffsetPlaceholder(op);
917     this->validate(initialOffset, size);
918     return offset;
919 }
920 
onClipRegion(const SkRegion & region,SkRegion::Op op)921 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
922 
923 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
924     fMCMgr.clipRegion(region, op);
925 #else
926     this->recordClipRegion(region, op);
927 #endif
928     this->INHERITED::onClipRegion(region, op);
929 }
930 
recordClipRegion(const SkRegion & region,SkRegion::Op op)931 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
932     // op + clip params + region
933     size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
934 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
935     size += kUInt32Size;    // + restore offset
936 #else
937     // recordRestoreOffsetPlaceholder doesn't always write an offset
938     if (!fRestoreOffsetStack.isEmpty()) {
939         // + restore offset
940         size += kUInt32Size;
941     }
942 #endif
943     size_t initialOffset = this->addDraw(CLIP_REGION, &size);
944     this->addRegion(region);
945     this->addInt(ClipParams_pack(op, false));
946     size_t offset = this->recordRestoreOffsetPlaceholder(op);
947 
948     this->validate(initialOffset, size);
949     return offset;
950 }
951 
clear(SkColor color)952 void SkPictureRecord::clear(SkColor color) {
953 
954 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
955     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
956 #endif
957 
958     // op + color
959     size_t size = 2 * kUInt32Size;
960     size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
961     this->addInt(color);
962     this->validate(initialOffset, size);
963 }
964 
drawPaint(const SkPaint & paint)965 void SkPictureRecord::drawPaint(const SkPaint& paint) {
966 
967 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
968     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
969 #endif
970 
971     // op + paint index
972     size_t size = 2 * kUInt32Size;
973     size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
974     SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
975     this->addPaint(paint);
976     this->validate(initialOffset, size);
977 }
978 
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)979 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
980                                  const SkPaint& paint) {
981 
982 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
983     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
984 #endif
985 
986     // op + paint index + mode + count + point data
987     size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
988     size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
989     SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
990     this->addPaint(paint);
991     if (paint.getPathEffect() != NULL) {
992         SkPathEffect::DashInfo info;
993         SkPathEffect::DashType dashType = paint.getPathEffect()->asADash(&info);
994         if (2 == count && SkPaint::kRound_Cap != paint.getStrokeCap() &&
995             SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
996             fContentInfo.incFastPathDashEffects();
997         }
998     }
999     this->addInt(mode);
1000     this->addInt(SkToInt(count));
1001     fWriter.writeMul4(pts, count * sizeof(SkPoint));
1002     this->validate(initialOffset, size);
1003 }
1004 
drawOval(const SkRect & oval,const SkPaint & paint)1005 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
1006 
1007 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1008     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1009 #endif
1010 
1011     // op + paint index + rect
1012     size_t size = 2 * kUInt32Size + sizeof(oval);
1013     size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
1014     SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
1015     this->addPaint(paint);
1016     this->addRect(oval);
1017     this->validate(initialOffset, size);
1018 }
1019 
drawRect(const SkRect & rect,const SkPaint & paint)1020 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
1021 
1022 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1023     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1024 #endif
1025 
1026     // op + paint index + rect
1027     size_t size = 2 * kUInt32Size + sizeof(rect);
1028     size_t initialOffset = this->addDraw(DRAW_RECT, &size);
1029     SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
1030     this->addPaint(paint);
1031     this->addRect(rect);
1032     this->validate(initialOffset, size);
1033 }
1034 
drawRRect(const SkRRect & rrect,const SkPaint & paint)1035 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
1036 
1037 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1038     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1039 #endif
1040 
1041     if (rrect.isRect() && kBeClever) {
1042         this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
1043     } else if (rrect.isOval() && kBeClever) {
1044         this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
1045     } else {
1046         // op + paint index + rrect
1047         size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
1048         size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
1049         SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
1050         this->addPaint(paint);
1051         this->addRRect(rrect);
1052         this->validate(initialOffset, size);
1053     }
1054 }
1055 
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)1056 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
1057                                    const SkPaint& paint) {
1058 
1059 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1060     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1061 #endif
1062 
1063     // op + paint index + rrects
1064     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
1065     size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
1066     SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
1067     this->addPaint(paint);
1068     this->addRRect(outer);
1069     this->addRRect(inner);
1070     this->validate(initialOffset, size);
1071 }
1072 
drawPath(const SkPath & path,const SkPaint & paint)1073 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
1074 
1075     if (paint.isAntiAlias() && !path.isConvex()) {
1076         fContentInfo.incAAConcavePaths();
1077 
1078         if (SkPaint::kStroke_Style == paint.getStyle() &&
1079             0 == paint.getStrokeWidth()) {
1080             fContentInfo.incAAHairlineConcavePaths();
1081         }
1082     }
1083 
1084 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1085     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1086 #endif
1087 
1088     // op + paint index + path index
1089     size_t size = 3 * kUInt32Size;
1090     size_t initialOffset = this->addDraw(DRAW_PATH, &size);
1091     SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
1092     this->addPaint(paint);
1093     this->addPath(path);
1094     this->validate(initialOffset, size);
1095 }
1096 
drawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint=NULL)1097 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
1098                                  const SkPaint* paint = NULL) {
1099     if (bitmap.drawsNothing() && kBeClever) {
1100         return;
1101     }
1102 
1103 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1104     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1105 #endif
1106 
1107     // op + paint index + bitmap index + left + top
1108     size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
1109     size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
1110     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
1111     this->addPaintPtr(paint);
1112     this->addBitmap(bitmap);
1113     this->addScalar(left);
1114     this->addScalar(top);
1115     this->validate(initialOffset, size);
1116 }
1117 
drawBitmapRectToRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,DrawBitmapRectFlags flags)1118 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
1119                                            const SkRect& dst, const SkPaint* paint,
1120                                            DrawBitmapRectFlags flags) {
1121     if (bitmap.drawsNothing() && kBeClever) {
1122         return;
1123     }
1124 
1125 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1126     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1127 #endif
1128     // id + paint index + bitmap index + bool for 'src' + flags
1129     size_t size = 5 * kUInt32Size;
1130     if (NULL != src) {
1131         size += sizeof(*src);   // + rect
1132     }
1133     size += sizeof(dst);        // + rect
1134 
1135     size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
1136     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
1137              == fWriter.bytesWritten());
1138     this->addPaintPtr(paint);
1139     this->addBitmap(bitmap);
1140     this->addRectPtr(src);  // may be null
1141     this->addRect(dst);
1142     this->addInt(flags);
1143     this->validate(initialOffset, size);
1144 }
1145 
drawBitmapMatrix(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint * paint)1146 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
1147                                        const SkPaint* paint) {
1148     if (bitmap.drawsNothing() && kBeClever) {
1149         return;
1150     }
1151 
1152 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1153     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1154 #endif
1155 
1156     // id + paint index + bitmap index + matrix
1157     size_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
1158     size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
1159     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
1160     this->addPaintPtr(paint);
1161     this->addBitmap(bitmap);
1162     this->addMatrix(matrix);
1163     this->validate(initialOffset, size);
1164 }
1165 
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)1166 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
1167                                      const SkRect& dst, const SkPaint* paint) {
1168     if (bitmap.drawsNothing() && kBeClever) {
1169         return;
1170     }
1171 
1172 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1173     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1174 #endif
1175 
1176     // op + paint index + bitmap id + center + dst rect
1177     size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
1178     size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
1179     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
1180     this->addPaintPtr(paint);
1181     this->addBitmap(bitmap);
1182     this->addIRect(center);
1183     this->addRect(dst);
1184     this->validate(initialOffset, size);
1185 }
1186 
drawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint * paint=NULL)1187 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
1188                                  const SkPaint* paint = NULL) {
1189     if (bitmap.drawsNothing() && kBeClever) {
1190         return;
1191     }
1192 
1193 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1194     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1195 #endif
1196 
1197     // op + paint index + bitmap index + left + top
1198     size_t size = 5 * kUInt32Size;
1199     size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
1200     SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
1201     this->addPaintPtr(paint);
1202     this->addBitmap(bitmap);
1203     this->addInt(left);
1204     this->addInt(top);
1205     this->validate(initialOffset, size);
1206 }
1207 
ComputeFontMetricsTopBottom(const SkPaint & paint,SkScalar topbot[2])1208 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
1209     SkPaint::FontMetrics metrics;
1210     paint.getFontMetrics(&metrics);
1211     SkRect bounds;
1212     // construct a rect so we can see any adjustments from the paint.
1213     // we use 0,1 for left,right, just so the rect isn't empty
1214     bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
1215     (void)paint.computeFastBounds(bounds, &bounds);
1216     topbot[0] = bounds.fTop;
1217     topbot[1] = bounds.fBottom;
1218 }
1219 
addFontMetricsTopBottom(const SkPaint & paint,const SkFlatData & flat,SkScalar minY,SkScalar maxY)1220 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
1221                                               SkScalar minY, SkScalar maxY) {
1222     WriteTopBot(paint, flat);
1223     this->addScalar(flat.topBot()[0] + minY);
1224     this->addScalar(flat.topBot()[1] + maxY);
1225 }
1226 
onDrawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)1227 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
1228                                  const SkPaint& paint) {
1229 
1230 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1231     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1232 #endif
1233 
1234     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1235 
1236     // op + paint index + length + 'length' worth of chars + x + y
1237     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1238     if (fast) {
1239         size += 2 * sizeof(SkScalar); // + top & bottom
1240     }
1241 
1242     DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
1243     size_t initialOffset = this->addDraw(op, &size);
1244     SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1245     const SkFlatData* flatPaintData = addPaint(paint);
1246     SkASSERT(flatPaintData);
1247     this->addText(text, byteLength);
1248     this->addScalar(x);
1249     this->addScalar(y);
1250     if (fast) {
1251         this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
1252     }
1253     this->validate(initialOffset, size);
1254 }
1255 
onDrawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)1256 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
1257                                     const SkPaint& paint) {
1258 
1259 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1260     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1261 #endif
1262 
1263     int points = paint.countText(text, byteLength);
1264     if (0 == points)
1265         return;
1266 
1267     bool canUseDrawH = true;
1268     SkScalar minY = pos[0].fY;
1269     SkScalar maxY = pos[0].fY;
1270     // check if the caller really should have used drawPosTextH()
1271     {
1272         const SkScalar firstY = pos[0].fY;
1273         for (int index = 1; index < points; index++) {
1274             if (pos[index].fY != firstY) {
1275                 canUseDrawH = false;
1276                 if (pos[index].fY < minY) {
1277                     minY = pos[index].fY;
1278                 } else if (pos[index].fY > maxY) {
1279                     maxY = pos[index].fY;
1280                 }
1281             }
1282         }
1283     }
1284 
1285     bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1286     bool fast = canUseDrawH && fastBounds && kBeClever;
1287 
1288     // op + paint index + length + 'length' worth of data + num points
1289     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1290     if (canUseDrawH) {
1291         if (fast) {
1292             size += 2 * sizeof(SkScalar); // + top & bottom
1293         }
1294         // + y-pos + actual x-point data
1295         size += sizeof(SkScalar) + points * sizeof(SkScalar);
1296     } else {
1297         // + x&y point data
1298         size += points * sizeof(SkPoint);
1299         if (fastBounds) {
1300             size += 2 * sizeof(SkScalar); // + top & bottom
1301         }
1302     }
1303 
1304     DrawType op;
1305     if (fast) {
1306         op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1307     } else if (canUseDrawH) {
1308         op = DRAW_POS_TEXT_H;
1309     } else if (fastBounds) {
1310         op = DRAW_POS_TEXT_TOP_BOTTOM;
1311     } else {
1312         op = DRAW_POS_TEXT;
1313     }
1314     size_t initialOffset = this->addDraw(op, &size);
1315     SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
1316     const SkFlatData* flatPaintData = this->addPaint(paint);
1317     SkASSERT(flatPaintData);
1318     this->addText(text, byteLength);
1319     this->addInt(points);
1320 
1321 #ifdef SK_DEBUG_SIZE
1322     size_t start = fWriter.bytesWritten();
1323 #endif
1324     if (canUseDrawH) {
1325         if (fast) {
1326             this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
1327         }
1328         this->addScalar(pos[0].fY);
1329         SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
1330         for (int index = 0; index < points; index++)
1331             *xptr++ = pos[index].fX;
1332     } else {
1333         fWriter.writeMul4(pos, points * sizeof(SkPoint));
1334         if (fastBounds) {
1335             this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
1336         }
1337     }
1338 #ifdef SK_DEBUG_SIZE
1339     fPointBytes += fWriter.bytesWritten() - start;
1340     fPointWrites += points;
1341 #endif
1342     this->validate(initialOffset, size);
1343 }
1344 
onDrawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)1345 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
1346                                      SkScalar constY, const SkPaint& paint) {
1347 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1348     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1349 #endif
1350 
1351     const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
1352     this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
1353 }
1354 
drawPosTextHImpl(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint,const SkFlatData * flatPaintData)1355 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
1356                           const SkScalar xpos[], SkScalar constY,
1357                           const SkPaint& paint, const SkFlatData* flatPaintData) {
1358     int points = paint.countText(text, byteLength);
1359     if (0 == points && kBeClever) {
1360         return;
1361     }
1362 
1363     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds() && kBeClever;
1364 
1365     // op + paint index + length + 'length' worth of data + num points
1366     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1367     if (fast) {
1368         size += 2 * sizeof(SkScalar); // + top & bottom
1369     }
1370     // + y + the actual points
1371     size += 1 * kUInt32Size + points * sizeof(SkScalar);
1372     size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
1373                                          &size);
1374     SkASSERT(flatPaintData);
1375     this->addFlatPaint(flatPaintData);
1376 
1377     this->addText(text, byteLength);
1378     this->addInt(points);
1379 
1380 #ifdef SK_DEBUG_SIZE
1381     size_t start = fWriter.bytesWritten();
1382 #endif
1383     if (fast) {
1384         this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
1385     }
1386     this->addScalar(constY);
1387     fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1388 #ifdef SK_DEBUG_SIZE
1389     fPointBytes += fWriter.bytesWritten() - start;
1390     fPointWrites += points;
1391 #endif
1392     this->validate(initialOffset, size);
1393 }
1394 
onDrawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)1395 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
1396                                        const SkMatrix* matrix, const SkPaint& paint) {
1397 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1398     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1399 #endif
1400 
1401     // op + paint index + length + 'length' worth of data + path index + matrix
1402     const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
1403     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
1404     size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
1405     SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
1406     this->addPaint(paint);
1407     this->addText(text, byteLength);
1408     this->addPath(path);
1409     this->addMatrix(m);
1410     this->validate(initialOffset, size);
1411 }
1412 
onDrawPicture(const SkPicture * picture)1413 void SkPictureRecord::onDrawPicture(const SkPicture* picture) {
1414 
1415 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1416     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1417 #endif
1418 
1419     // op + picture index
1420     size_t size = 2 * kUInt32Size;
1421     size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
1422     this->addPicture(picture);
1423     this->validate(initialOffset, size);
1424 }
1425 
drawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode * xfer,const uint16_t indices[],int indexCount,const SkPaint & paint)1426 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1427                           const SkPoint vertices[], const SkPoint texs[],
1428                           const SkColor colors[], SkXfermode* xfer,
1429                           const uint16_t indices[], int indexCount,
1430                           const SkPaint& paint) {
1431 
1432 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1433     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1434 #endif
1435 
1436     uint32_t flags = 0;
1437     if (texs) {
1438         flags |= DRAW_VERTICES_HAS_TEXS;
1439     }
1440     if (colors) {
1441         flags |= DRAW_VERTICES_HAS_COLORS;
1442     }
1443     if (indexCount > 0) {
1444         flags |= DRAW_VERTICES_HAS_INDICES;
1445     }
1446     if (NULL != xfer) {
1447         SkXfermode::Mode mode;
1448         if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
1449             flags |= DRAW_VERTICES_HAS_XFER;
1450         }
1451     }
1452 
1453     // op + paint index + flags + vmode + vCount + vertices
1454     size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1455     if (flags & DRAW_VERTICES_HAS_TEXS) {
1456         size += vertexCount * sizeof(SkPoint);  // + uvs
1457     }
1458     if (flags & DRAW_VERTICES_HAS_COLORS) {
1459         size += vertexCount * sizeof(SkColor);  // + vert colors
1460     }
1461     if (flags & DRAW_VERTICES_HAS_INDICES) {
1462         // + num indices + indices
1463         size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1464     }
1465     if (flags & DRAW_VERTICES_HAS_XFER) {
1466         size += kUInt32Size;    // mode enum
1467     }
1468 
1469     size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
1470     SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
1471     this->addPaint(paint);
1472     this->addInt(flags);
1473     this->addInt(vmode);
1474     this->addInt(vertexCount);
1475     this->addPoints(vertices, vertexCount);
1476     if (flags & DRAW_VERTICES_HAS_TEXS) {
1477         this->addPoints(texs, vertexCount);
1478     }
1479     if (flags & DRAW_VERTICES_HAS_COLORS) {
1480         fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1481     }
1482     if (flags & DRAW_VERTICES_HAS_INDICES) {
1483         this->addInt(indexCount);
1484         fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1485     }
1486     if (flags & DRAW_VERTICES_HAS_XFER) {
1487         SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
1488         (void)xfer->asMode(&mode);
1489         this->addInt(mode);
1490     }
1491     this->validate(initialOffset, size);
1492 }
1493 
drawData(const void * data,size_t length)1494 void SkPictureRecord::drawData(const void* data, size_t length) {
1495 
1496 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
1497     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
1498 #endif
1499 
1500     // op + length + 'length' worth of data
1501     size_t size = 2 * kUInt32Size + SkAlign4(length);
1502     size_t initialOffset = this->addDraw(DRAW_DATA, &size);
1503     this->addInt(SkToInt(length));
1504     fWriter.writePad(data, length);
1505     this->validate(initialOffset, size);
1506 }
1507 
beginCommentGroup(const char * description)1508 void SkPictureRecord::beginCommentGroup(const char* description) {
1509     // op/size + length of string + \0 terminated chars
1510     size_t length = strlen(description);
1511     size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
1512     size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
1513     fWriter.writeString(description, length);
1514     this->validate(initialOffset, size);
1515 }
1516 
addComment(const char * kywd,const char * value)1517 void SkPictureRecord::addComment(const char* kywd, const char* value) {
1518     // op/size + 2x length of string + 2x \0 terminated chars
1519     size_t kywdLen = strlen(kywd);
1520     size_t valueLen = strlen(value);
1521     size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
1522     size_t initialOffset = this->addDraw(COMMENT, &size);
1523     fWriter.writeString(kywd, kywdLen);
1524     fWriter.writeString(value, valueLen);
1525     this->validate(initialOffset, size);
1526 }
1527 
endCommentGroup()1528 void SkPictureRecord::endCommentGroup() {
1529     // op/size
1530     size_t size = 1 * kUInt32Size;
1531     size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1532     this->validate(initialOffset, size);
1533 }
1534 
1535 // [op/size] [rect] [skip offset]
1536 static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
onPushCull(const SkRect & cullRect)1537 void SkPictureRecord::onPushCull(const SkRect& cullRect) {
1538     size_t size = kPushCullOpSize;
1539     size_t initialOffset = this->addDraw(PUSH_CULL, &size);
1540     // PUSH_CULL's size should stay constant (used to rewind).
1541     SkASSERT(size == kPushCullOpSize);
1542 
1543     this->addRect(cullRect);
1544     fCullOffsetStack.push(SkToU32(fWriter.bytesWritten()));
1545     this->addInt(0);
1546     this->validate(initialOffset, size);
1547 }
1548 
onPopCull()1549 void SkPictureRecord::onPopCull() {
1550     SkASSERT(!fCullOffsetStack.isEmpty());
1551 
1552     uint32_t cullSkipOffset = fCullOffsetStack.top();
1553     fCullOffsetStack.pop();
1554 
1555     // Collapse empty push/pop pairs.
1556     if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten() && kBeClever) {
1557         SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
1558         SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
1559         fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
1560         return;
1561     }
1562 
1563     // op only
1564     size_t size = kUInt32Size;
1565     size_t initialOffset = this->addDraw(POP_CULL, &size);
1566 
1567     // update the cull skip offset to point past this op.
1568     fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten()));
1569 
1570     this->validate(initialOffset, size);
1571 }
1572 
1573 ///////////////////////////////////////////////////////////////////////////////
1574 
onNewSurface(const SkImageInfo & info)1575 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
1576     return NULL;
1577 }
1578 
addBitmap(const SkBitmap & bitmap)1579 int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
1580     const int index = fBitmapHeap->insert(bitmap);
1581     // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1582     // release builds, the invalid value will be recorded so that the reader will know that there
1583     // was a problem.
1584     SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1585     this->addInt(index);
1586     return index;
1587 }
1588 
addMatrix(const SkMatrix & matrix)1589 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1590     fWriter.writeMatrix(matrix);
1591 }
1592 
getFlatPaintData(const SkPaint & paint)1593 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
1594     return fPaints.findAndReturnFlat(paint);
1595 }
1596 
addPaintPtr(const SkPaint * paint)1597 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1598     if (NULL != paint && NULL != paint->getPathEffect()) {
1599         fContentInfo.incPaintWithPathEffectUses();
1600     }
1601 
1602     const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
1603     this->addFlatPaint(data);
1604     return data;
1605 }
1606 
addFlatPaint(const SkFlatData * flatPaint)1607 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
1608     int index = flatPaint ? flatPaint->index() : 0;
1609     this->addInt(index);
1610 }
1611 
addPathToHeap(const SkPath & path)1612 int SkPictureRecord::addPathToHeap(const SkPath& path) {
1613     if (NULL == fPathHeap) {
1614         fPathHeap.reset(SkNEW(SkPathHeap));
1615     }
1616 #ifdef SK_DEDUP_PICTURE_PATHS
1617     return fPathHeap->insert(path);
1618 #else
1619     return fPathHeap->append(path);
1620 #endif
1621 }
1622 
addPath(const SkPath & path)1623 void SkPictureRecord::addPath(const SkPath& path) {
1624     this->addInt(this->addPathToHeap(path));
1625 }
1626 
addPicture(const SkPicture * picture)1627 void SkPictureRecord::addPicture(const SkPicture* picture) {
1628     int index = fPictureRefs.find(picture);
1629     if (index < 0) {    // not found
1630         index = fPictureRefs.count();
1631         *fPictureRefs.append() = picture;
1632         picture->ref();
1633     }
1634     // follow the convention of recording a 1-based index
1635     this->addInt(index + 1);
1636 }
1637 
addPoint(const SkPoint & point)1638 void SkPictureRecord::addPoint(const SkPoint& point) {
1639 #ifdef SK_DEBUG_SIZE
1640     size_t start = fWriter.bytesWritten();
1641 #endif
1642     fWriter.writePoint(point);
1643 #ifdef SK_DEBUG_SIZE
1644     fPointBytes += fWriter.bytesWritten() - start;
1645     fPointWrites++;
1646 #endif
1647 }
1648 
addPoints(const SkPoint pts[],int count)1649 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1650     fWriter.writeMul4(pts, count * sizeof(SkPoint));
1651 #ifdef SK_DEBUG_SIZE
1652     fPointBytes += count * sizeof(SkPoint);
1653     fPointWrites++;
1654 #endif
1655 }
1656 
addNoOp()1657 void SkPictureRecord::addNoOp() {
1658     size_t size = kUInt32Size; // op
1659     this->addDraw(NOOP, &size);
1660 }
1661 
addRect(const SkRect & rect)1662 void SkPictureRecord::addRect(const SkRect& rect) {
1663 #ifdef SK_DEBUG_SIZE
1664     size_t start = fWriter.bytesWritten();
1665 #endif
1666     fWriter.writeRect(rect);
1667 #ifdef SK_DEBUG_SIZE
1668     fRectBytes += fWriter.bytesWritten() - start;
1669     fRectWrites++;
1670 #endif
1671 }
1672 
addRectPtr(const SkRect * rect)1673 void SkPictureRecord::addRectPtr(const SkRect* rect) {
1674     if (fWriter.writeBool(rect != NULL)) {
1675         fWriter.writeRect(*rect);
1676     }
1677 }
1678 
addIRect(const SkIRect & rect)1679 void SkPictureRecord::addIRect(const SkIRect& rect) {
1680     fWriter.write(&rect, sizeof(rect));
1681 }
1682 
addIRectPtr(const SkIRect * rect)1683 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1684     if (fWriter.writeBool(rect != NULL)) {
1685         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1686     }
1687 }
1688 
addRRect(const SkRRect & rrect)1689 void SkPictureRecord::addRRect(const SkRRect& rrect) {
1690     fWriter.writeRRect(rrect);
1691 }
1692 
addRegion(const SkRegion & region)1693 void SkPictureRecord::addRegion(const SkRegion& region) {
1694     fWriter.writeRegion(region);
1695 }
1696 
addText(const void * text,size_t byteLength)1697 void SkPictureRecord::addText(const void* text, size_t byteLength) {
1698 #ifdef SK_DEBUG_SIZE
1699     size_t start = fWriter.bytesWritten();
1700 #endif
1701     addInt(SkToInt(byteLength));
1702     fWriter.writePad(text, byteLength);
1703 #ifdef SK_DEBUG_SIZE
1704     fTextBytes += fWriter.bytesWritten() - start;
1705     fTextWrites++;
1706 #endif
1707 }
1708 
1709 ///////////////////////////////////////////////////////////////////////////////
1710 
1711 #ifdef SK_DEBUG_SIZE
size() const1712 size_t SkPictureRecord::size() const {
1713     size_t result = 0;
1714     size_t sizeData;
1715     bitmaps(&sizeData);
1716     result += sizeData;
1717     matrices(&sizeData);
1718     result += sizeData;
1719     paints(&sizeData);
1720     result += sizeData;
1721     paths(&sizeData);
1722     result += sizeData;
1723     pictures(&sizeData);
1724     result += sizeData;
1725     regions(&sizeData);
1726     result += sizeData;
1727     result += streamlen();
1728     return result;
1729 }
1730 
bitmaps(size_t * size) const1731 int SkPictureRecord::bitmaps(size_t* size) const {
1732     size_t result = 0;
1733     int count = fBitmaps.count();
1734     for (int index = 0; index < count; index++)
1735         result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1736     *size = result;
1737     return count;
1738 }
1739 
matrices(size_t * size) const1740 int SkPictureRecord::matrices(size_t* size) const {
1741     int count = fMatrices.count();
1742     *size = sizeof(fMatrices[0]) * count;
1743     return count;
1744 }
1745 
paints(size_t * size) const1746 int SkPictureRecord::paints(size_t* size) const {
1747     size_t result = 0;
1748     int count = fPaints.count();
1749     for (int index = 0; index < count; index++)
1750         result += sizeof(fPaints[index]) + fPaints[index]->size();
1751     *size = result;
1752     return count;
1753 }
1754 
paths(size_t * size) const1755 int SkPictureRecord::paths(size_t* size) const {
1756     size_t result = 0;
1757     int count = fPaths.count();
1758     for (int index = 0; index < count; index++)
1759         result += sizeof(fPaths[index]) + fPaths[index]->size();
1760     *size = result;
1761     return count;
1762 }
1763 
regions(size_t * size) const1764 int SkPictureRecord::regions(size_t* size) const {
1765     size_t result = 0;
1766     int count = fRegions.count();
1767     for (int index = 0; index < count; index++)
1768         result += sizeof(fRegions[index]) + fRegions[index]->size();
1769     *size = result;
1770     return count;
1771 }
1772 
streamlen() const1773 size_t SkPictureRecord::streamlen() const {
1774     return fWriter.size();
1775 }
1776 #endif
1777 
1778 #ifdef SK_DEBUG_VALIDATE
validate(uint32_t initialOffset,uint32_t size) const1779 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1780     SkASSERT(fWriter.size() == initialOffset + size);
1781 
1782     validateBitmaps();
1783     validateMatrices();
1784     validatePaints();
1785     validatePaths();
1786     validateRegions();
1787 }
1788 
validateBitmaps() const1789 void SkPictureRecord::validateBitmaps() const {
1790     int count = fBitmapHeap->count();
1791     SkASSERT((unsigned) count < 0x1000);
1792     for (int index = 0; index < count; index++) {
1793         const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
1794         SkASSERT(bitPtr);
1795         bitPtr->validate();
1796     }
1797 }
1798 
validateMatrices() const1799 void SkPictureRecord::validateMatrices() const {
1800     int count = fMatrices.count();
1801     SkASSERT((unsigned) count < 0x1000);
1802     for (int index = 0; index < count; index++) {
1803         const SkFlatData* matrix = fMatrices[index];
1804         SkASSERT(matrix);
1805 //        matrix->validate();
1806     }
1807 }
1808 
validatePaints() const1809 void SkPictureRecord::validatePaints() const {
1810     int count = fPaints.count();
1811     SkASSERT((unsigned) count < 0x1000);
1812     for (int index = 0; index < count; index++) {
1813         const SkFlatData* paint = fPaints[index];
1814         SkASSERT(paint);
1815 //            paint->validate();
1816     }
1817 }
1818 
validatePaths() const1819 void SkPictureRecord::validatePaths() const {
1820     if (NULL == fPathHeap) {
1821         return;
1822     }
1823 
1824     int count = fPathHeap->count();
1825     SkASSERT((unsigned) count < 0x1000);
1826     for (int index = 0; index < count; index++) {
1827         const SkPath& path = (*fPathHeap)[index];
1828         path.validate();
1829     }
1830 }
1831 
validateRegions() const1832 void SkPictureRecord::validateRegions() const {
1833     int count = fRegions.count();
1834     SkASSERT((unsigned) count < 0x1000);
1835     for (int index = 0; index < count; index++) {
1836         const SkFlatData* region = fRegions[index];
1837         SkASSERT(region);
1838 //        region->validate();
1839     }
1840 }
1841 #endif
1842