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