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