SkPictureRecord.cpp revision eed779d866e1e239bfb9ebc6a225b7345a41adf9
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
19enum {
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.
25static int const kUInt32Size = 4;
26
27static const uint32_t kSaveSize = 2 * kUInt32Size;
28static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
30
31SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* 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
56SkPictureRecord::~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)
70static 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
141SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
142    SkASSERT(!"eeek, don't try to change the device on a recording canvas");
143    return this->INHERITED::setDevice(device);
144}
145
146int 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.size());
150
151    // op + flags
152    uint32_t size = kSaveSize;
153    uint32_t initialOffset = this->addDraw(SAVE, &size);
154    addInt(flags);
155
156    validate(initialOffset, size);
157    return this->INHERITED::save(flags);
158}
159
160int 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.size());
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    uint32_t initialOffset = this->addDraw(SAVE_LAYER, &size);
177    addRectPtr(bounds);
178    SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.size());
179    addPaintPtr(paint);
180    addInt(flags);
181
182    if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
183        fFirstSavedLayerIndex = fRestoreOffsetStack.count();
184    }
185
186    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
198bool 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 */
205static 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?
222static 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.
236struct 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 */
249static bool match(SkWriter32* writer, uint32_t offset,
250                  int* pattern, CommandInfo* result, int numCommands) {
251    SkASSERT(offset < writer->size());
252
253    uint32_t curOffset = offset;
254    uint32_t curSize = 0;
255    int numMatched;
256    for (numMatched = 0; numMatched < numCommands && curOffset < writer->size(); ++numMatched) {
257        DrawType op = peek_op_and_size(writer, curOffset, &curSize);
258        while (NOOP == op && curOffset < writer->size()) {
259            curOffset += curSize;
260            op = peek_op_and_size(writer, curOffset, &curSize);
261        }
262
263        if (curOffset >= writer->size()) {
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->size()) {
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
297static 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 */
310static 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 */
339static 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 */
348static 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 */
428static 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 */
461static 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->size();
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
518typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
519                                     SkPaintDictionary* paintDict);
520enum PictureRecordOptType {
521    kRewind_OptType,  // Optimization rewinds the command stream
522    kCollapseSaveLayer_OptType,  // Optimization eliminates a save/restore pair
523};
524
525struct PictureRecordOpt {
526    PictureRecordOptProc fProc;
527    PictureRecordOptType fType;
528};
529/*
530 * A list of the optimizations that are tried upon seeing a restore
531 * TODO: add a real API for such optimizations
532 *       Add the ability to fire optimizations on any op (not just RESTORE)
533 */
534static const PictureRecordOpt gPictureRecordOpts[] = {
535    { collapse_save_clip_restore, kRewind_OptType },
536    { remove_save_layer1,         kCollapseSaveLayer_OptType },
537    { remove_save_layer2,         kCollapseSaveLayer_OptType }
538};
539
540// This is called after an optimization has been applied to the command stream
541// in order to adjust the contents and state of the bounding box hierarchy and
542// state tree to reflect the optimization.
543static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
544                                      SkBBoxHierarchy* boundingHierarchy) {
545    switch (opt) {
546    case kCollapseSaveLayer_OptType:
547        if (NULL != stateTree) {
548            stateTree->saveCollapsed();
549        }
550        break;
551    case kRewind_OptType:
552        if (NULL != boundingHierarchy) {
553            boundingHierarchy->rewindInserts();
554        }
555        // Note: No need to touch the state tree for this to work correctly.
556        // Unused branches do not burden the playback, and pruning the tree
557        // would be O(N^2), so it is best to leave it alone.
558        break;
559    default:
560        SkASSERT(0);
561    }
562}
563
564void SkPictureRecord::restore() {
565    // FIXME: SkDeferredCanvas needs to be refactored to respect
566    // save/restore balancing so that the following test can be
567    // turned on permanently.
568#if 0
569    SkASSERT(fRestoreOffsetStack.count() > 1);
570#endif
571
572    // check for underflow
573    if (fRestoreOffsetStack.count() == 0) {
574        return;
575    }
576
577    if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
578        fFirstSavedLayerIndex = kNoSavedLayerIndex;
579    }
580
581    uint32_t initialOffset, size;
582    size_t opt = 0;
583    if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) {
584        for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
585            if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
586                // Some optimization fired so don't add the RESTORE
587                size = 0;
588                initialOffset = fWriter.size();
589                apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
590                                          fStateTree, fBoundingHierarchy);
591                break;
592            }
593        }
594    }
595
596    if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) ||
597        SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
598        // No optimization fired so add the RESTORE
599        fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
600        size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
601        initialOffset = this->addDraw(RESTORE, &size);
602    }
603
604    fRestoreOffsetStack.pop();
605
606    validate(initialOffset, size);
607    return this->INHERITED::restore();
608}
609
610bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
611    // op + dx + dy
612    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
613    uint32_t initialOffset = this->addDraw(TRANSLATE, &size);
614    addScalar(dx);
615    addScalar(dy);
616    validate(initialOffset, size);
617    return this->INHERITED::translate(dx, dy);
618}
619
620bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
621    // op + sx + sy
622    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
623    uint32_t initialOffset = this->addDraw(SCALE, &size);
624    addScalar(sx);
625    addScalar(sy);
626    validate(initialOffset, size);
627    return this->INHERITED::scale(sx, sy);
628}
629
630bool SkPictureRecord::rotate(SkScalar degrees) {
631    // op + degrees
632    uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
633    uint32_t initialOffset = this->addDraw(ROTATE, &size);
634    addScalar(degrees);
635    validate(initialOffset, size);
636    return this->INHERITED::rotate(degrees);
637}
638
639bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
640    // op + sx + sy
641    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
642    uint32_t initialOffset = this->addDraw(SKEW, &size);
643    addScalar(sx);
644    addScalar(sy);
645    validate(initialOffset, size);
646    return this->INHERITED::skew(sx, sy);
647}
648
649bool SkPictureRecord::concat(const SkMatrix& matrix) {
650    validate(fWriter.size(), 0);
651    // op + matrix index
652    uint32_t size = 2 * kUInt32Size;
653    uint32_t initialOffset = this->addDraw(CONCAT, &size);
654    addMatrix(matrix);
655    validate(initialOffset, size);
656    return this->INHERITED::concat(matrix);
657}
658
659void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
660    validate(fWriter.size(), 0);
661    // op + matrix index
662    uint32_t size = 2 * kUInt32Size;
663    uint32_t initialOffset = this->addDraw(SET_MATRIX, &size);
664    addMatrix(matrix);
665    validate(initialOffset, size);
666    this->INHERITED::setMatrix(matrix);
667}
668
669static bool regionOpExpands(SkRegion::Op op) {
670    switch (op) {
671        case SkRegion::kUnion_Op:
672        case SkRegion::kXOR_Op:
673        case SkRegion::kReverseDifference_Op:
674        case SkRegion::kReplace_Op:
675            return true;
676        case SkRegion::kIntersect_Op:
677        case SkRegion::kDifference_Op:
678            return false;
679        default:
680            SkDEBUGFAIL("unknown region op");
681            return false;
682    }
683}
684
685void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
686    int32_t offset = fRestoreOffsetStack.top();
687    while (offset > 0) {
688        uint32_t* peek = fWriter.peek32(offset);
689        offset = *peek;
690        *peek = restoreOffset;
691    }
692
693#ifdef SK_DEBUG
694    // assert that the final offset value points to a save verb
695    uint32_t opSize;
696    DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
697    SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
698#endif
699}
700
701void SkPictureRecord::beginRecording() {
702    // we have to call this *after* our constructor, to ensure that it gets
703    // recorded. This is balanced by restoreToCount() call from endRecording,
704    // which in-turn calls our overridden restore(), so those get recorded too.
705    fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
706}
707
708void SkPictureRecord::endRecording() {
709    SkASSERT(kNoInitialSave != fInitialSaveCount);
710    this->restoreToCount(fInitialSaveCount);
711}
712
713void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
714    if (fRestoreOffsetStack.isEmpty()) {
715        return;
716    }
717
718    if (regionOpExpands(op)) {
719        // Run back through any previous clip ops, and mark their offset to
720        // be 0, disabling their ability to trigger a jump-to-restore, otherwise
721        // they could hide this clips ability to expand the clip (i.e. go from
722        // empty to non-empty).
723        fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
724    }
725
726    size_t offset = fWriter.size();
727    // The RestoreOffset field is initially filled with a placeholder
728    // value that points to the offset of the previous RestoreOffset
729    // in the current stack level, thus forming a linked list so that
730    // the restore offsets can be filled in when the corresponding
731    // restore command is recorded.
732    addInt(fRestoreOffsetStack.top());
733    fRestoreOffsetStack.top() = offset;
734}
735
736bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
737    // id + rect + clip params
738    uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
739    // recordRestoreOffsetPlaceholder doesn't always write an offset
740    if (!fRestoreOffsetStack.isEmpty()) {
741        // + restore offset
742        size += kUInt32Size;
743    }
744    uint32_t initialOffset = this->addDraw(CLIP_RECT, &size);
745    addRect(rect);
746    addInt(ClipParams_pack(op, doAA));
747    recordRestoreOffsetPlaceholder(op);
748
749    validate(initialOffset, size);
750    return this->INHERITED::clipRect(rect, op, doAA);
751}
752
753bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
754    if (rrect.isRect()) {
755        return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
756    }
757
758    // op + rrect + clip params
759    uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
760    // recordRestoreOffsetPlaceholder doesn't always write an offset
761    if (!fRestoreOffsetStack.isEmpty()) {
762        // + restore offset
763        size += kUInt32Size;
764    }
765    uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size);
766    addRRect(rrect);
767    addInt(ClipParams_pack(op, doAA));
768    recordRestoreOffsetPlaceholder(op);
769
770    validate(initialOffset, size);
771
772    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
773        return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
774    } else {
775        return this->INHERITED::clipRRect(rrect, op, doAA);
776    }
777}
778
779bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
780
781    SkRect r;
782    if (!path.isInverseFillType() && path.isRect(&r)) {
783        return this->clipRect(r, op, doAA);
784    }
785
786    // op + path index + clip params
787    uint32_t size = 3 * kUInt32Size;
788    // recordRestoreOffsetPlaceholder doesn't always write an offset
789    if (!fRestoreOffsetStack.isEmpty()) {
790        // + restore offset
791        size += kUInt32Size;
792    }
793    uint32_t initialOffset = this->addDraw(CLIP_PATH, &size);
794    addPath(path);
795    addInt(ClipParams_pack(op, doAA));
796    recordRestoreOffsetPlaceholder(op);
797
798    validate(initialOffset, size);
799
800    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
801        return this->updateClipConservativelyUsingBounds(path.getBounds(), op,
802                                                         path.isInverseFillType());
803    } else {
804        return this->INHERITED::clipPath(path, op, doAA);
805    }
806}
807
808bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
809    // op + region index + clip params
810    uint32_t size = 3 * kUInt32Size;
811    // recordRestoreOffsetPlaceholder doesn't always write an offset
812    if (!fRestoreOffsetStack.isEmpty()) {
813        // + restore offset
814        size += kUInt32Size;
815    }
816    uint32_t initialOffset = this->addDraw(CLIP_REGION, &size);
817    addRegion(region);
818    addInt(ClipParams_pack(op, false));
819    recordRestoreOffsetPlaceholder(op);
820
821    validate(initialOffset, size);
822    return this->INHERITED::clipRegion(region, op);
823}
824
825void SkPictureRecord::clear(SkColor color) {
826    // op + color
827    uint32_t size = 2 * kUInt32Size;
828    uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
829    addInt(color);
830    validate(initialOffset, size);
831}
832
833void SkPictureRecord::drawPaint(const SkPaint& paint) {
834    // op + paint index
835    uint32_t size = 2 * kUInt32Size;
836    uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size);
837    SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size());
838    addPaint(paint);
839    validate(initialOffset, size);
840}
841
842void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
843                                 const SkPaint& paint) {
844    // op + paint index + mode + count + point data
845    uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
846    uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size);
847    SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size());
848    addPaint(paint);
849    addInt(mode);
850    addInt(count);
851    fWriter.writeMul4(pts, count * sizeof(SkPoint));
852    validate(initialOffset, size);
853}
854
855void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
856    // op + paint index + rect
857    uint32_t size = 2 * kUInt32Size + sizeof(oval);
858    uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size);
859    SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size());
860    addPaint(paint);
861    addRect(oval);
862    validate(initialOffset, size);
863}
864
865void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
866    // op + paint index + rect
867    uint32_t size = 2 * kUInt32Size + sizeof(rect);
868    uint32_t initialOffset = this->addDraw(DRAW_RECT, &size);
869    SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size());
870    addPaint(paint);
871    addRect(rect);
872    validate(initialOffset, size);
873}
874
875void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
876    if (rrect.isRect()) {
877        this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
878    } else if (rrect.isOval()) {
879        this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
880    } else {
881        // op + paint index + rrect
882        uint32_t initialOffset, size;
883        size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
884        initialOffset = this->addDraw(DRAW_RRECT, &size);
885        SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size());
886        addPaint(paint);
887        addRRect(rrect);
888        validate(initialOffset, size);
889    }
890}
891
892void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
893    // op + paint index + path index
894    uint32_t size = 3 * kUInt32Size;
895    uint32_t initialOffset = this->addDraw(DRAW_PATH, &size);
896    SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size());
897    addPaint(paint);
898    addPath(path);
899    validate(initialOffset, size);
900}
901
902void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
903                        const SkPaint* paint = NULL) {
904    // op + paint index + bitmap index + left + top
905    uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
906    uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
907    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size());
908    addPaintPtr(paint);
909    addBitmap(bitmap);
910    addScalar(left);
911    addScalar(top);
912    validate(initialOffset, size);
913}
914
915void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
916                                           const SkRect& dst, const SkPaint* paint,
917                                           DrawBitmapRectFlags flags) {
918    // id + paint index + bitmap index + bool for 'src' + flags
919    uint32_t size = 5 * kUInt32Size;
920    if (NULL != src) {
921        size += sizeof(*src);   // + rect
922    }
923    size += sizeof(dst);        // + rect
924
925    uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
926    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size());
927    addPaintPtr(paint);
928    addBitmap(bitmap);
929    addRectPtr(src);  // may be null
930    addRect(dst);
931    addInt(flags);
932    validate(initialOffset, size);
933}
934
935void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
936                                       const SkPaint* paint) {
937    // id + paint index + bitmap index + matrix index
938    uint32_t size = 4 * kUInt32Size;
939    uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
940    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size());
941    addPaintPtr(paint);
942    addBitmap(bitmap);
943    addMatrix(matrix);
944    validate(initialOffset, size);
945}
946
947void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
948                                     const SkRect& dst, const SkPaint* paint) {
949    // op + paint index + bitmap id + center + dst rect
950    uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
951    uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
952    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size());
953    addPaintPtr(paint);
954    addBitmap(bitmap);
955    addIRect(center);
956    addRect(dst);
957    validate(initialOffset, size);
958}
959
960void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
961                        const SkPaint* paint = NULL) {
962    // op + paint index + bitmap index + left + top
963    uint32_t size = 5 * kUInt32Size;
964    uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
965    SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size());
966    addPaintPtr(paint);
967    addBitmap(bitmap);
968    addInt(left);
969    addInt(top);
970    validate(initialOffset, size);
971}
972
973// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
974// tweaked by paint.computeFastBounds().
975//
976static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
977    SkPaint::FontMetrics metrics;
978    paint.getFontMetrics(&metrics);
979    SkRect bounds;
980    // construct a rect so we can see any adjustments from the paint.
981    // we use 0,1 for left,right, just so the rect isn't empty
982    bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
983    (void)paint.computeFastBounds(bounds, &bounds);
984    topbot[0] = bounds.fTop;
985    topbot[1] = bounds.fBottom;
986}
987
988void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
989                                              SkScalar minY, SkScalar maxY) {
990    if (!flat.isTopBotWritten()) {
991        computeFontMetricsTopBottom(paint, flat.writableTopBot());
992        SkASSERT(flat.isTopBotWritten());
993    }
994    addScalar(flat.topBot()[0] + minY);
995    addScalar(flat.topBot()[1] + maxY);
996}
997
998void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
999                      SkScalar y, const SkPaint& paint) {
1000    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1001
1002    // op + paint index + length + 'length' worth of chars + x + y
1003    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
1004    if (fast) {
1005        size += 2 * sizeof(SkScalar); // + top & bottom
1006    }
1007
1008    DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
1009    uint32_t initialOffset = this->addDraw(op, &size);
1010    SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
1011    const SkFlatData* flatPaintData = addPaint(paint);
1012    SkASSERT(flatPaintData);
1013    addText(text, byteLength);
1014    addScalar(x);
1015    addScalar(y);
1016    if (fast) {
1017        addFontMetricsTopBottom(paint, *flatPaintData, y, y);
1018    }
1019    validate(initialOffset, size);
1020}
1021
1022void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
1023                         const SkPoint pos[], const SkPaint& paint) {
1024    size_t points = paint.countText(text, byteLength);
1025    if (0 == points)
1026        return;
1027
1028    bool canUseDrawH = true;
1029    SkScalar minY = pos[0].fY;
1030    SkScalar maxY = pos[0].fY;
1031    // check if the caller really should have used drawPosTextH()
1032    {
1033        const SkScalar firstY = pos[0].fY;
1034        for (size_t index = 1; index < points; index++) {
1035            if (pos[index].fY != firstY) {
1036                canUseDrawH = false;
1037                if (pos[index].fY < minY) {
1038                    minY = pos[index].fY;
1039                } else if (pos[index].fY > maxY) {
1040                    maxY = pos[index].fY;
1041                }
1042            }
1043        }
1044    }
1045
1046    bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
1047    bool fast = canUseDrawH && fastBounds;
1048
1049    // op + paint index + length + 'length' worth of data + num points
1050    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1051    if (canUseDrawH) {
1052        if (fast) {
1053            size += 2 * sizeof(SkScalar); // + top & bottom
1054        }
1055        // + y-pos + actual x-point data
1056        size += sizeof(SkScalar) + points * sizeof(SkScalar);
1057    } else {
1058        // + x&y point data
1059        size += points * sizeof(SkPoint);
1060        if (fastBounds) {
1061            size += 2 * sizeof(SkScalar); // + top & bottom
1062        }
1063    }
1064
1065    DrawType op;
1066    if (fast) {
1067        op = DRAW_POS_TEXT_H_TOP_BOTTOM;
1068    } else if (canUseDrawH) {
1069        op = DRAW_POS_TEXT_H;
1070    } else if (fastBounds) {
1071        op = DRAW_POS_TEXT_TOP_BOTTOM;
1072    } else {
1073        op = DRAW_POS_TEXT;
1074    }
1075    uint32_t initialOffset = this->addDraw(op, &size);
1076    SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size());
1077    const SkFlatData* flatPaintData = addPaint(paint);
1078    SkASSERT(flatPaintData);
1079    addText(text, byteLength);
1080    addInt(points);
1081
1082#ifdef SK_DEBUG_SIZE
1083    size_t start = fWriter.size();
1084#endif
1085    if (canUseDrawH) {
1086        if (fast) {
1087            addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
1088        }
1089        addScalar(pos[0].fY);
1090        SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
1091        for (size_t index = 0; index < points; index++)
1092            *xptr++ = pos[index].fX;
1093    } else {
1094        fWriter.writeMul4(pos, points * sizeof(SkPoint));
1095        if (fastBounds) {
1096            addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
1097        }
1098    }
1099#ifdef SK_DEBUG_SIZE
1100    fPointBytes += fWriter.size() - start;
1101    fPointWrites += points;
1102#endif
1103    validate(initialOffset, size);
1104}
1105
1106void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
1107                          const SkScalar xpos[], SkScalar constY,
1108                          const SkPaint& paint) {
1109    size_t points = paint.countText(text, byteLength);
1110    if (0 == points)
1111        return;
1112
1113    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
1114
1115    // op + paint index + length + 'length' worth of data + num points
1116    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
1117    if (fast) {
1118        size += 2 * sizeof(SkScalar); // + top & bottom
1119    }
1120    // + y + the actual points
1121    size += 1 * kUInt32Size + points * sizeof(SkScalar);
1122
1123    uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
1124                                           &size);
1125    const SkFlatData* flatPaintData = addPaint(paint);
1126    SkASSERT(flatPaintData);
1127    addText(text, byteLength);
1128    addInt(points);
1129
1130#ifdef SK_DEBUG_SIZE
1131    size_t start = fWriter.size();
1132#endif
1133    if (fast) {
1134        addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
1135    }
1136    addScalar(constY);
1137    fWriter.writeMul4(xpos, points * sizeof(SkScalar));
1138#ifdef SK_DEBUG_SIZE
1139    fPointBytes += fWriter.size() - start;
1140    fPointWrites += points;
1141#endif
1142    validate(initialOffset, size);
1143}
1144
1145void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
1146                            const SkPath& path, const SkMatrix* matrix,
1147                            const SkPaint& paint) {
1148    // op + paint index + length + 'length' worth of data + path index + matrix index
1149    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size;
1150    uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
1151    SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size());
1152    addPaint(paint);
1153    addText(text, byteLength);
1154    addPath(path);
1155    addMatrixPtr(matrix);
1156    validate(initialOffset, size);
1157}
1158
1159void SkPictureRecord::drawPicture(SkPicture& picture) {
1160    // op + picture index
1161    uint32_t size = 2 * kUInt32Size;
1162    uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
1163    addPicture(picture);
1164    validate(initialOffset, size);
1165}
1166
1167void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
1168                          const SkPoint vertices[], const SkPoint texs[],
1169                          const SkColor colors[], SkXfermode*,
1170                          const uint16_t indices[], int indexCount,
1171                          const SkPaint& paint) {
1172    uint32_t flags = 0;
1173    if (texs) {
1174        flags |= DRAW_VERTICES_HAS_TEXS;
1175    }
1176    if (colors) {
1177        flags |= DRAW_VERTICES_HAS_COLORS;
1178    }
1179    if (indexCount > 0) {
1180        flags |= DRAW_VERTICES_HAS_INDICES;
1181    }
1182
1183    // op + paint index + flags + vmode + vCount + vertices
1184    uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
1185    if (flags & DRAW_VERTICES_HAS_TEXS) {
1186        size += vertexCount * sizeof(SkPoint);  // + uvs
1187    }
1188    if (flags & DRAW_VERTICES_HAS_COLORS) {
1189        size += vertexCount * sizeof(SkColor);  // + vert colors
1190    }
1191    if (flags & DRAW_VERTICES_HAS_INDICES) {
1192        // + num indices + indices
1193        size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
1194    }
1195
1196    uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
1197    SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size());
1198    addPaint(paint);
1199    addInt(flags);
1200    addInt(vmode);
1201    addInt(vertexCount);
1202    addPoints(vertices, vertexCount);
1203    if (flags & DRAW_VERTICES_HAS_TEXS) {
1204        addPoints(texs, vertexCount);
1205    }
1206    if (flags & DRAW_VERTICES_HAS_COLORS) {
1207        fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
1208    }
1209    if (flags & DRAW_VERTICES_HAS_INDICES) {
1210        addInt(indexCount);
1211        fWriter.writePad(indices, indexCount * sizeof(uint16_t));
1212    }
1213    validate(initialOffset, size);
1214}
1215
1216void SkPictureRecord::drawData(const void* data, size_t length) {
1217    // op + length + 'length' worth of data
1218    uint32_t size = 2 * kUInt32Size + SkAlign4(length);
1219    uint32_t initialOffset = this->addDraw(DRAW_DATA, &size);
1220    addInt(length);
1221    fWriter.writePad(data, length);
1222    validate(initialOffset, size);
1223}
1224
1225void SkPictureRecord::beginCommentGroup(const char* description) {
1226    // op/size + length of string + \0 terminated chars
1227    int length = strlen(description);
1228    uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
1229    uint32_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
1230    fWriter.writeString(description, length);
1231    validate(initialOffset, size);
1232}
1233
1234void SkPictureRecord::addComment(const char* kywd, const char* value) {
1235    // op/size + 2x length of string + 2x \0 terminated chars
1236    int kywdLen = strlen(kywd);
1237    int valueLen = strlen(value);
1238    uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
1239    uint32_t initialOffset = this->addDraw(COMMENT, &size);
1240    fWriter.writeString(kywd, kywdLen);
1241    fWriter.writeString(value, valueLen);
1242    validate(initialOffset, size);
1243}
1244
1245void SkPictureRecord::endCommentGroup() {
1246    // op/size
1247    uint32_t size = 1 * kUInt32Size;
1248    uint32_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
1249    validate(initialOffset, size);
1250}
1251
1252///////////////////////////////////////////////////////////////////////////////
1253
1254void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
1255    const int index = fBitmapHeap->insert(bitmap);
1256    // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
1257    // release builds, the invalid value will be recorded so that the reader will know that there
1258    // was a problem.
1259    SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
1260    addInt(index);
1261}
1262
1263void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
1264    addMatrixPtr(&matrix);
1265}
1266
1267void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
1268    this->addInt(matrix ? fMatrices.find(*matrix) : 0);
1269}
1270
1271const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
1272    const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
1273    int index = data ? data->index() : 0;
1274    this->addInt(index);
1275    return data;
1276}
1277
1278void SkPictureRecord::addPath(const SkPath& path) {
1279    if (NULL == fPathHeap) {
1280        fPathHeap = SkNEW(SkPathHeap);
1281    }
1282    addInt(fPathHeap->append(path));
1283}
1284
1285void SkPictureRecord::addPicture(SkPicture& picture) {
1286    int index = fPictureRefs.find(&picture);
1287    if (index < 0) {    // not found
1288        index = fPictureRefs.count();
1289        *fPictureRefs.append() = &picture;
1290        picture.ref();
1291    }
1292    // follow the convention of recording a 1-based index
1293    addInt(index + 1);
1294}
1295
1296void SkPictureRecord::addPoint(const SkPoint& point) {
1297#ifdef SK_DEBUG_SIZE
1298    size_t start = fWriter.size();
1299#endif
1300    fWriter.writePoint(point);
1301#ifdef SK_DEBUG_SIZE
1302    fPointBytes += fWriter.size() - start;
1303    fPointWrites++;
1304#endif
1305}
1306
1307void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
1308    fWriter.writeMul4(pts, count * sizeof(SkPoint));
1309#ifdef SK_DEBUG_SIZE
1310    fPointBytes += count * sizeof(SkPoint);
1311    fPointWrites++;
1312#endif
1313}
1314
1315void SkPictureRecord::addRect(const SkRect& rect) {
1316#ifdef SK_DEBUG_SIZE
1317    size_t start = fWriter.size();
1318#endif
1319    fWriter.writeRect(rect);
1320#ifdef SK_DEBUG_SIZE
1321    fRectBytes += fWriter.size() - start;
1322    fRectWrites++;
1323#endif
1324}
1325
1326void SkPictureRecord::addRectPtr(const SkRect* rect) {
1327    if (fWriter.writeBool(rect != NULL)) {
1328        fWriter.writeRect(*rect);
1329    }
1330}
1331
1332void SkPictureRecord::addIRect(const SkIRect& rect) {
1333    fWriter.write(&rect, sizeof(rect));
1334}
1335
1336void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
1337    if (fWriter.writeBool(rect != NULL)) {
1338        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
1339    }
1340}
1341
1342void SkPictureRecord::addRRect(const SkRRect& rrect) {
1343    fWriter.writeRRect(rrect);
1344}
1345
1346void SkPictureRecord::addRegion(const SkRegion& region) {
1347    addInt(fRegions.find(region));
1348}
1349
1350void SkPictureRecord::addText(const void* text, size_t byteLength) {
1351#ifdef SK_DEBUG_SIZE
1352    size_t start = fWriter.size();
1353#endif
1354    addInt(byteLength);
1355    fWriter.writePad(text, byteLength);
1356#ifdef SK_DEBUG_SIZE
1357    fTextBytes += fWriter.size() - start;
1358    fTextWrites++;
1359#endif
1360}
1361
1362///////////////////////////////////////////////////////////////////////////////
1363
1364#ifdef SK_DEBUG_SIZE
1365size_t SkPictureRecord::size() const {
1366    size_t result = 0;
1367    size_t sizeData;
1368    bitmaps(&sizeData);
1369    result += sizeData;
1370    matrices(&sizeData);
1371    result += sizeData;
1372    paints(&sizeData);
1373    result += sizeData;
1374    paths(&sizeData);
1375    result += sizeData;
1376    pictures(&sizeData);
1377    result += sizeData;
1378    regions(&sizeData);
1379    result += sizeData;
1380    result += streamlen();
1381    return result;
1382}
1383
1384int SkPictureRecord::bitmaps(size_t* size) const {
1385    size_t result = 0;
1386    int count = fBitmaps.count();
1387    for (int index = 0; index < count; index++)
1388        result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
1389    *size = result;
1390    return count;
1391}
1392
1393int SkPictureRecord::matrices(size_t* size) const {
1394    int count = fMatrices.count();
1395    *size = sizeof(fMatrices[0]) * count;
1396    return count;
1397}
1398
1399int SkPictureRecord::paints(size_t* size) const {
1400    size_t result = 0;
1401    int count = fPaints.count();
1402    for (int index = 0; index < count; index++)
1403        result += sizeof(fPaints[index]) + fPaints[index]->size();
1404    *size = result;
1405    return count;
1406}
1407
1408int SkPictureRecord::paths(size_t* size) const {
1409    size_t result = 0;
1410    int count = fPaths.count();
1411    for (int index = 0; index < count; index++)
1412        result += sizeof(fPaths[index]) + fPaths[index]->size();
1413    *size = result;
1414    return count;
1415}
1416
1417int SkPictureRecord::regions(size_t* size) const {
1418    size_t result = 0;
1419    int count = fRegions.count();
1420    for (int index = 0; index < count; index++)
1421        result += sizeof(fRegions[index]) + fRegions[index]->size();
1422    *size = result;
1423    return count;
1424}
1425
1426size_t SkPictureRecord::streamlen() const {
1427    return fWriter.size();
1428}
1429#endif
1430
1431#ifdef SK_DEBUG_VALIDATE
1432void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
1433    SkASSERT(fWriter.size() == initialOffset + size);
1434
1435    validateBitmaps();
1436    validateMatrices();
1437    validatePaints();
1438    validatePaths();
1439    validateRegions();
1440}
1441
1442void SkPictureRecord::validateBitmaps() const {
1443    int count = fBitmapHeap->count();
1444    SkASSERT((unsigned) count < 0x1000);
1445    for (int index = 0; index < count; index++) {
1446        const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
1447        SkASSERT(bitPtr);
1448        bitPtr->validate();
1449    }
1450}
1451
1452void SkPictureRecord::validateMatrices() const {
1453    int count = fMatrices.count();
1454    SkASSERT((unsigned) count < 0x1000);
1455    for (int index = 0; index < count; index++) {
1456        const SkFlatData* matrix = fMatrices[index];
1457        SkASSERT(matrix);
1458//        matrix->validate();
1459    }
1460}
1461
1462void SkPictureRecord::validatePaints() const {
1463    int count = fPaints.count();
1464    SkASSERT((unsigned) count < 0x1000);
1465    for (int index = 0; index < count; index++) {
1466        const SkFlatData* paint = fPaints[index];
1467        SkASSERT(paint);
1468//            paint->validate();
1469    }
1470}
1471
1472void SkPictureRecord::validatePaths() const {
1473    if (NULL == fPathHeap) {
1474        return;
1475    }
1476
1477    int count = fPathHeap->count();
1478    SkASSERT((unsigned) count < 0x1000);
1479    for (int index = 0; index < count; index++) {
1480        const SkPath& path = (*fPathHeap)[index];
1481        path.validate();
1482    }
1483}
1484
1485void SkPictureRecord::validateRegions() const {
1486    int count = fRegions.count();
1487    SkASSERT((unsigned) count < 0x1000);
1488    for (int index = 0; index < count; index++) {
1489        const SkFlatData* region = fRegions[index];
1490        SkASSERT(region);
1491//        region->validate();
1492    }
1493}
1494#endif
1495