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