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