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