gfx/skia/trunk/src/core/SkPictureRecord.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /*
     2  * Copyright 2011 Google Inc.
     3  *
     4  * Use of this source code is governed by a BSD-style license that can be
     5  * found in the LICENSE file.
     6  */
     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 "SkOffsetTable.h"
    15 #include "SkPictureStateTree.h"
    16 #include "SkSurface.h"
    18 #define HEAP_BLOCK_SIZE 4096
    20 enum {
    21     // just need a value that save or getSaveCount would never return
    22     kNoInitialSave = -1,
    23 };
    25 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
    26 static int const kUInt32Size = 4;
    28 static const uint32_t kSaveSize = 2 * kUInt32Size;
    29 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
    30 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
    32 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
    33     : INHERITED(dimensions.width(), dimensions.height())
    34     , fBoundingHierarchy(NULL)
    35     , fStateTree(NULL)
    36     , fFlattenableHeap(HEAP_BLOCK_SIZE)
    37     , fPaints(&fFlattenableHeap)
    38     , fRecordFlags(flags)
    39     , fOptsEnabled(true) {
    40 #ifdef SK_DEBUG_SIZE
    41     fPointBytes = fRectBytes = fTextBytes = 0;
    42     fPointWrites = fRectWrites = fTextWrites = 0;
    43 #endif
    45     fBitmapHeap = SkNEW(SkBitmapHeap);
    46     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
    47     fPathHeap = NULL;   // lazy allocate
    49 #ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
    50     fFirstSavedLayerIndex = kNoSavedLayerIndex;
    51 #endif
    53     fInitialSaveCount = kNoInitialSave;
    55 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
    56     fMCMgr.init(this);
    57 #endif
    58 }
    60 SkPictureRecord::~SkPictureRecord() {
    61     SkSafeUnref(fBitmapHeap);
    62     SkSafeUnref(fPathHeap);
    63     SkSafeUnref(fBoundingHierarchy);
    64     SkSafeUnref(fStateTree);
    65     fFlattenableHeap.setBitmapStorage(NULL);
    66     fPictureRefs.unrefAll();
    67 }
    69 ///////////////////////////////////////////////////////////////////////////////
    71 // Return the offset of the paint inside a given op's byte stream. A zero
    72 // return value means there is no paint (and you really shouldn't be calling
    73 // this method)
    74 static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
    75     // These offsets are where the paint would be if the op size doesn't overflow
    76     static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
    77         0,  // UNUSED - no paint
    78         0,  // CLIP_PATH - no paint
    79         0,  // CLIP_REGION - no paint
    80         0,  // CLIP_RECT - no paint
    81         0,  // CLIP_RRECT - no paint
    82         0,  // CONCAT - no paint
    83         1,  // DRAW_BITMAP - right after op code
    84         1,  // DRAW_BITMAP_MATRIX - right after op code
    85         1,  // DRAW_BITMAP_NINE - right after op code
    86         1,  // DRAW_BITMAP_RECT_TO_RECT - right after op code
    87         0,  // DRAW_CLEAR - no paint
    88         0,  // DRAW_DATA - no paint
    89         1,  // DRAW_OVAL - right after op code
    90         1,  // DRAW_PAINT - right after op code
    91         1,  // DRAW_PATH - right after op code
    92         0,  // DRAW_PICTURE - no paint
    93         1,  // DRAW_POINTS - right after op code
    94         1,  // DRAW_POS_TEXT - right after op code
    95         1,  // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
    96         1,  // DRAW_POS_TEXT_H - right after op code
    97         1,  // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
    98         1,  // DRAW_RECT - right after op code
    99         1,  // DRAW_RRECT - right after op code
   100         1,  // DRAW_SPRITE - right after op code
   101         1,  // DRAW_TEXT - right after op code
   102         1,  // DRAW_TEXT_ON_PATH - right after op code
   103         1,  // DRAW_TEXT_TOP_BOTTOM - right after op code
   104         1,  // DRAW_VERTICES - right after op code
   105         0,  // RESTORE - no paint
   106         0,  // ROTATE - no paint
   107         0,  // SAVE - no paint
   108         0,  // SAVE_LAYER - see below - this paint's location varies
   109         0,  // SCALE - no paint
   110         0,  // SET_MATRIX - no paint
   111         0,  // SKEW - no paint
   112         0,  // TRANSLATE - no paint
   113         0,  // NOOP - no paint
   114         0,  // BEGIN_GROUP - no paint
   115         0,  // COMMENT - no paint
   116         0,  // END_GROUP - no paint
   117         1,  // DRAWDRRECT - right after op code
   118         0,  // PUSH_CULL - no paint
   119         0,  // POP_CULL - no paint
   120     };
   122     SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
   123                       need_to_be_in_sync);
   124     SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
   126     int overflow = 0;
   127     if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
   128         // This op's size overflows so an extra uint32_t will be written
   129         // after the op code
   130         overflow = sizeof(uint32_t);
   131     }
   133     if (SAVE_LAYER == op) {
   134         static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
   135         static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
   137         if (kSaveLayerNoBoundsSize == opSize) {
   138             return kSaveLayerNoBoundsPaintOffset + overflow;
   139         } else {
   140             SkASSERT(kSaveLayerWithBoundsSize == opSize);
   141             return kSaveLayerWithBoundsPaintOffset + overflow;
   142         }
   143     }
   145     SkASSERT(0 != gPaintOffsets[op]);   // really shouldn't be calling this method
   146     return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
   147 }
   149 void SkPictureRecord::willSave(SaveFlags flags) {
   151 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   152     fMCMgr.save(flags);
   153 #else
   154     // record the offset to us, making it non-positive to distinguish a save
   155     // from a clip entry.
   156     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
   157     this->recordSave(flags);
   158 #endif
   160     this->INHERITED::willSave(flags);
   161 }
   163 void SkPictureRecord::recordSave(SaveFlags flags) {
   164     // op + flags
   165     uint32_t size = kSaveSize;
   166     size_t initialOffset = this->addDraw(SAVE, &size);
   167     this->addInt(flags);
   169     this->validate(initialOffset, size);
   170 }
   172 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
   173                                                            const SkPaint* paint, SaveFlags flags) {
   175 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   176     fMCMgr.saveLayer(bounds, paint, flags);
   177 #else
   178     // record the offset to us, making it non-positive to distinguish a save
   179     // from a clip entry.
   180     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
   181     this->recordSaveLayer(bounds, paint, flags);
   182     if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
   183         fFirstSavedLayerIndex = fRestoreOffsetStack.count();
   184     }
   185 #endif
   187     this->INHERITED::willSaveLayer(bounds, paint, flags);
   188     /*  No need for a (potentially very big) layer 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     return kNoLayer_SaveLayerStrategy;
   194 }
   196 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
   197                                       SaveFlags flags) {
   198     // op + bool for 'bounds'
   199     uint32_t size = 2 * kUInt32Size;
   200     if (NULL != bounds) {
   201         size += sizeof(*bounds); // + rect
   202     }
   203     // + paint index + flags
   204     size += 2 * kUInt32Size;
   206     SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
   208     size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
   209     this->addRectPtr(bounds);
   210     SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
   211     this->addPaintPtr(paint);
   212     this->addInt(flags);
   214     this->validate(initialOffset, size);
   215 }
   217 bool SkPictureRecord::isDrawingToLayer() const {
   218 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   219     return fMCMgr.isDrawingToLayer();
   220 #else
   221     return fFirstSavedLayerIndex != kNoSavedLayerIndex;
   222 #endif
   223 }
   225 /*
   226  * Read the op code from 'offset' in 'writer'.
   227  */
   228 #ifdef SK_DEBUG
   229 static DrawType peek_op(SkWriter32* writer, int32_t offset) {
   230     return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
   231 }
   232 #endif
   234 /*
   235  * Read the op code from 'offset' in 'writer' and extract the size too.
   236  */
   237 static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
   238     uint32_t peek = writer->readTAt<uint32_t>(offset);
   240     uint32_t op;
   241     UNPACK_8_24(peek, op, *size);
   242     if (MASK_24 == *size) {
   243         // size required its own slot right after the op code
   244         *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
   245     }
   246     return (DrawType) op;
   247 }
   249 #ifdef TRACK_COLLAPSE_STATS
   250     static int gCollapseCount, gCollapseCalls;
   251 #endif
   253 // Is the supplied paint simply a color?
   254 static bool is_simple(const SkPaint& p) {
   255     intptr_t orAccum = (intptr_t)p.getPathEffect()  |
   256                        (intptr_t)p.getShader()      |
   257                        (intptr_t)p.getXfermode()    |
   258                        (intptr_t)p.getMaskFilter()  |
   259                        (intptr_t)p.getColorFilter() |
   260                        (intptr_t)p.getRasterizer()  |
   261                        (intptr_t)p.getLooper()      |
   262                        (intptr_t)p.getImageFilter();
   263     return 0 == orAccum;
   264 }
   266 // CommandInfos are fed to the 'match' method and filled in with command
   267 // information.
   268 struct CommandInfo {
   269     DrawType fActualOp;
   270     uint32_t fOffset;
   271     uint32_t fSize;
   272 };
   274 /*
   275  * Attempt to match the provided pattern of commands starting at 'offset'
   276  * in the byte stream and stopping at the end of the stream. Upon success,
   277  * return true with all the pattern information filled out in the result
   278  * array (i.e., actual ops, offsets and sizes).
   279  * Note this method skips any NOOPs seen in the stream
   280  */
   281 static bool match(SkWriter32* writer, uint32_t offset,
   282                   int* pattern, CommandInfo* result, int numCommands) {
   283     SkASSERT(offset < writer->bytesWritten());
   285     uint32_t curOffset = offset;
   286     uint32_t curSize = 0;
   287     int numMatched;
   288     for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
   289         DrawType op = peek_op_and_size(writer, curOffset, &curSize);
   290         while (NOOP == op && curOffset < writer->bytesWritten()) {
   291             curOffset += curSize;
   292             op = peek_op_and_size(writer, curOffset, &curSize);
   293         }
   295         if (curOffset >= writer->bytesWritten()) {
   296             return false; // ran out of byte stream
   297         }
   299         if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
   300             if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
   301                 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
   302                 return false;
   303             }
   304         } else if (op != pattern[numMatched]) {
   305             return false;
   306         }
   308         result[numMatched].fActualOp = op;
   309         result[numMatched].fOffset = curOffset;
   310         result[numMatched].fSize = curSize;
   312         curOffset += curSize;
   313     }
   315     if (numMatched != numCommands) {
   316         return false;
   317     }
   319     curOffset += curSize;
   320     if (curOffset < writer->bytesWritten()) {
   321         // Something else between the last command and the end of the stream
   322         return false;
   323     }
   325     return true;
   326 }
   328 // temporarily here to make code review easier
   329 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
   330                                                  SkPaintDictionary* paintDict,
   331                                                  const CommandInfo& saveLayerInfo,
   332                                                  const CommandInfo& dbmInfo);
   334 /*
   335  * Restore has just been called (but not recorded), look back at the
   336  * matching save* and see if we are in the configuration:
   337  *   SAVE_LAYER
   338  *       DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
   339  *   RESTORE
   340  * where the saveLayer's color can be moved into the drawBitmap*'s paint
   341  */
   342 static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
   343                                SkPaintDictionary* paintDict) {
   344     // back up to the save block
   345     // TODO: add a stack to track save*/restore offsets rather than searching backwards
   346     while (offset > 0) {
   347         offset = writer->readTAt<uint32_t>(offset);
   348     }
   350     int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
   351     CommandInfo result[SK_ARRAY_COUNT(pattern)];
   353     if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
   354         return false;
   355     }
   357     if (kSaveLayerWithBoundsSize == result[0].fSize) {
   358         // The saveLayer's bound can offset where the dbm is drawn
   359         return false;
   360     }
   362     return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
   363                                                 result[0], result[1]);
   364 }
   366 /*
   367  * Convert the command code located at 'offset' to a NOOP. Leave the size
   368  * field alone so the NOOP can be skipped later.
   369  */
   370 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
   371     uint32_t command = writer->readTAt<uint32_t>(offset);
   372     writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
   373 }
   375 /*
   376  * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
   377  * Return true on success; false otherwise.
   378  */
   379 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
   380                                                  SkPaintDictionary* paintDict,
   381                                                  const CommandInfo& saveLayerInfo,
   382                                                  const CommandInfo& dbmInfo) {
   383     SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
   384     SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
   385              DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
   386              DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
   387              DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
   389     uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
   390     uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
   392     // we have a match, now we need to get the paints involved
   393     uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
   394     uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
   396     if (0 == saveLayerPaintId) {
   397         // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
   398         // and signal the caller (by returning true) to not add the RESTORE op
   399         convert_command_to_noop(writer, saveLayerInfo.fOffset);
   400         return true;
   401     }
   403     if (0 == dbmPaintId) {
   404         // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
   405         // and signal the caller (by returning true) to not add the RESTORE op
   406         convert_command_to_noop(writer, saveLayerInfo.fOffset);
   407         writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
   408         return true;
   409     }
   411     SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
   412     if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
   413         return false;
   414     }
   416     // For this optimization we only fold the saveLayer and drawBitmapRect
   417     // together if the saveLayer's draw is simple (i.e., no fancy effects) and
   418     // and the only difference in the colors is that the saveLayer's can have
   419     // an alpha while the drawBitmapRect's is opaque.
   420     // TODO: it should be possible to fold them together even if they both
   421     // have different non-255 alphas
   422     SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
   424     SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
   425     if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
   426         return false;
   427     }
   429     SkColor newColor = SkColorSetA(dbmPaint->getColor(),
   430                                    SkColorGetA(saveLayerPaint->getColor()));
   431     dbmPaint->setColor(newColor);
   433     const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
   434     if (NULL == data) {
   435         return false;
   436     }
   438     // kill the saveLayer and alter the DBMR2R's paint to be the modified one
   439     convert_command_to_noop(writer, saveLayerInfo.fOffset);
   440     writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
   441     return true;
   442 }
   444 /*
   445  * Restore has just been called (but not recorded), look back at the
   446  * matching save* and see if we are in the configuration:
   447  *   SAVE_LAYER (with NULL == bounds)
   448  *      SAVE
   449  *         CLIP_RECT
   450  *         DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
   451  *      RESTORE
   452  *   RESTORE
   453  * where the saveLayer's color can be moved into the drawBitmap*'s paint
   454  */
   455 static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
   456                                SkPaintDictionary* paintDict) {
   458     // back up to the save block
   459     // TODO: add a stack to track save*/restore offsets rather than searching backwards
   460     while (offset > 0) {
   461         offset = writer->readTAt<uint32_t>(offset);
   462     }
   464     int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
   465     CommandInfo result[SK_ARRAY_COUNT(pattern)];
   467     if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
   468         return false;
   469     }
   471     if (kSaveLayerWithBoundsSize == result[0].fSize) {
   472         // The saveLayer's bound can offset where the dbm is drawn
   473         return false;
   474     }
   476     return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
   477                                                 result[0], result[3]);
   478 }
   480 static bool is_drawing_op(DrawType op) {
   481     return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
   482 }
   484 /*
   485  *  Restore has just been called (but not recorded), so look back at the
   486  *  matching save(), and see if we can eliminate the pair of them, due to no
   487  *  intervening matrix/clip calls.
   488  *
   489  *  If so, update the writer and return true, in which case we won't even record
   490  *  the restore() call. If we still need the restore(), return false.
   491  */
   492 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
   493                                        SkPaintDictionary* paintDict) {
   494 #ifdef TRACK_COLLAPSE_STATS
   495     gCollapseCalls += 1;
   496 #endif
   498     int32_t restoreOffset = (int32_t)writer->bytesWritten();
   500     // back up to the save block
   501     while (offset > 0) {
   502         offset = writer->readTAt<uint32_t>(offset);
   503     }
   505     // now offset points to a save
   506     offset = -offset;
   507     uint32_t opSize;
   508     DrawType op = peek_op_and_size(writer, offset, &opSize);
   509     if (SAVE_LAYER == op) {
   510         // not ready to cull these out yet (mrr)
   511         return false;
   512     }
   513     SkASSERT(SAVE == op);
   514     SkASSERT(kSaveSize == opSize);
   516     // get the save flag (last 4-bytes of the space allocated for the opSize)
   517     SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
   518     if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
   519         // This function's optimization is only correct for kMatrixClip style saves.
   520         // TODO: set checkMatrix & checkClip booleans here and then check for the
   521         // offending operations in the following loop.
   522         return false;
   523     }
   525     // Walk forward until we get back to either a draw-verb (abort) or we hit
   526     // our restore (success).
   527     int32_t saveOffset = offset;
   529     offset += opSize;
   530     while (offset < restoreOffset) {
   531         op = peek_op_and_size(writer, offset, &opSize);
   532         if (is_drawing_op(op) || (SAVE_LAYER == op)) {
   533             // drawing verb, abort
   534             return false;
   535         }
   536         offset += opSize;
   537     }
   539 #ifdef TRACK_COLLAPSE_STATS
   540     gCollapseCount += 1;
   541     SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
   542              (double)gCollapseCount / gCollapseCalls, "%");
   543 #endif
   545     writer->rewindToOffset(saveOffset);
   546     return true;
   547 }
   549 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
   550                                      SkPaintDictionary* paintDict);
   551 enum PictureRecordOptType {
   552     kRewind_OptType,  // Optimization rewinds the command stream
   553     kCollapseSaveLayer_OptType,  // Optimization eliminates a save/restore pair
   554 };
   556 enum PictureRecordOptFlags {
   557     kSkipIfBBoxHierarchy_Flag = 0x1,  // Optimization should be skipped if the
   558                                       // SkPicture has a bounding box hierarchy.
   559 };
   561 struct PictureRecordOpt {
   562     PictureRecordOptProc fProc;
   563     PictureRecordOptType fType;
   564     unsigned fFlags;
   565 };
   566 /*
   567  * A list of the optimizations that are tried upon seeing a restore
   568  * TODO: add a real API for such optimizations
   569  *       Add the ability to fire optimizations on any op (not just RESTORE)
   570  */
   571 static const PictureRecordOpt gPictureRecordOpts[] = {
   572     // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
   573     // because it is redundant with the state traversal optimization in
   574     // SkPictureStateTree, and applying the optimization introduces significant
   575     // record time overhead because it requires rewinding contents that were
   576     // recorded into the BBoxHierarchy.
   577     { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
   578     { remove_save_layer1,         kCollapseSaveLayer_OptType, 0 },
   579     { remove_save_layer2,         kCollapseSaveLayer_OptType, 0 }
   580 };
   582 // This is called after an optimization has been applied to the command stream
   583 // in order to adjust the contents and state of the bounding box hierarchy and
   584 // state tree to reflect the optimization.
   585 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
   586                                       SkBBoxHierarchy* boundingHierarchy) {
   587     switch (opt) {
   588     case kCollapseSaveLayer_OptType:
   589         if (NULL != stateTree) {
   590             stateTree->saveCollapsed();
   591         }
   592         break;
   593     case kRewind_OptType:
   594         if (NULL != boundingHierarchy) {
   595             boundingHierarchy->rewindInserts();
   596         }
   597         // Note: No need to touch the state tree for this to work correctly.
   598         // Unused branches do not burden the playback, and pruning the tree
   599         // would be O(N^2), so it is best to leave it alone.
   600         break;
   601     default:
   602         SkASSERT(0);
   603     }
   604 }
   606 void SkPictureRecord::willRestore() {
   607     // FIXME: SkDeferredCanvas needs to be refactored to respect
   608     // save/restore balancing so that the following test can be
   609     // turned on permanently.
   610 #if 0
   611     SkASSERT(fRestoreOffsetStack.count() > 1);
   612 #endif
   614 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   615     if (fMCMgr.getSaveCount() == 1) {
   616         return;
   617     }
   619     fMCMgr.restore();
   620 #else
   621     // check for underflow
   622     if (fRestoreOffsetStack.count() == 0) {
   623         return;
   624     }
   626     if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
   627         fFirstSavedLayerIndex = kNoSavedLayerIndex;
   628     }
   630     size_t opt = 0;
   631     if (fOptsEnabled) {
   632         for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
   633             if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
   634                 && NULL != fBoundingHierarchy) {
   635                 continue;
   636             }
   637             if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
   638                 // Some optimization fired so don't add the RESTORE
   639                 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
   640                                           fStateTree, fBoundingHierarchy);
   641                 break;
   642             }
   643         }
   644     }
   646     if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
   647         // No optimization fired so add the RESTORE
   648         this->recordRestore();
   649     }
   651     fRestoreOffsetStack.pop();
   652 #endif
   654     this->INHERITED::willRestore();
   655 }
   657 void SkPictureRecord::recordRestore(bool fillInSkips) {
   658     uint32_t initialOffset, size;
   659     if (fillInSkips) {
   660         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
   661     }
   662     size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
   663     initialOffset = this->addDraw(RESTORE, &size);
   664     this->validate(initialOffset, size);
   665 }
   667 void SkPictureRecord::didTranslate(SkScalar dx, SkScalar dy) {
   668 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   669     fMCMgr.translate(dx, dy);
   670 #else
   671     // op + dx + dy
   672     uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
   673     size_t initialOffset = this->addDraw(TRANSLATE, &size);
   674     this->addScalar(dx);
   675     this->addScalar(dy);
   676     this->validate(initialOffset, size);
   677 #endif
   678     this->INHERITED::didTranslate(dx, dy);
   679 }
   681 void SkPictureRecord::didScale(SkScalar sx, SkScalar sy) {
   683 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   684     fMCMgr.scale(sx, sy);
   685 #else
   686     // op + sx + sy
   687     uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
   688     size_t initialOffset = this->addDraw(SCALE, &size);
   689     this->addScalar(sx);
   690     this->addScalar(sy);
   691     this->validate(initialOffset, size);
   692 #endif
   693     this->INHERITED::didScale(sx, sy);
   694 }
   696 void SkPictureRecord::didRotate(SkScalar degrees) {
   698 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   699     fMCMgr.rotate(degrees);
   700 #else
   701     // op + degrees
   702     uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
   703     size_t initialOffset = this->addDraw(ROTATE, &size);
   704     this->addScalar(degrees);
   705     this->validate(initialOffset, size);
   706 #endif
   707     this->INHERITED::didRotate(degrees);
   708 }
   710 void SkPictureRecord::didSkew(SkScalar sx, SkScalar sy) {
   712 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   713     fMCMgr.skew(sx, sy);
   714 #else
   715     // op + sx + sy
   716     uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
   717     size_t initialOffset = this->addDraw(SKEW, &size);
   718     this->addScalar(sx);
   719     this->addScalar(sy);
   720     this->validate(initialOffset, size);
   721 #endif
   722     this->INHERITED::didSkew(sx, sy);
   723 }
   725 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
   727 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   728     fMCMgr.concat(matrix);
   729 #else
   730     this->recordConcat(matrix);
   731 #endif
   732     this->INHERITED::didConcat(matrix);
   733 }
   735 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
   736     this->validate(fWriter.bytesWritten(), 0);
   737     // op + matrix
   738     uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
   739     size_t initialOffset = this->addDraw(CONCAT, &size);
   740     this->addMatrix(matrix);
   741     this->validate(initialOffset, size);
   742 }
   744 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
   746 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   747     fMCMgr.setMatrix(matrix);
   748 #else
   749     this->validate(fWriter.bytesWritten(), 0);
   750     // op + matrix
   751     uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
   752     size_t initialOffset = this->addDraw(SET_MATRIX, &size);
   753     this->addMatrix(matrix);
   754     this->validate(initialOffset, size);
   755 #endif
   756     this->INHERITED::didSetMatrix(matrix);
   757 }
   759 static bool regionOpExpands(SkRegion::Op op) {
   760     switch (op) {
   761         case SkRegion::kUnion_Op:
   762         case SkRegion::kXOR_Op:
   763         case SkRegion::kReverseDifference_Op:
   764         case SkRegion::kReplace_Op:
   765             return true;
   766         case SkRegion::kIntersect_Op:
   767         case SkRegion::kDifference_Op:
   768             return false;
   769         default:
   770             SkDEBUGFAIL("unknown region op");
   771             return false;
   772     }
   773 }
   775 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   776 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
   777     fMCMgr.fillInSkips(&fWriter, restoreOffset);
   778 }
   779 #else
   780 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
   781     int32_t offset = fRestoreOffsetStack.top();
   782     while (offset > 0) {
   783         uint32_t peek = fWriter.readTAt<uint32_t>(offset);
   784         fWriter.overwriteTAt(offset, restoreOffset);
   785         offset = peek;
   786     }
   788 #ifdef SK_DEBUG
   789     // assert that the final offset value points to a save verb
   790     uint32_t opSize;
   791     DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
   792     SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
   793 #endif
   794 }
   795 #endif
   797 void SkPictureRecord::beginRecording() {
   798     // we have to call this *after* our constructor, to ensure that it gets
   799     // recorded. This is balanced by restoreToCount() call from endRecording,
   800     // which in-turn calls our overridden restore(), so those get recorded too.
   801     fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
   802 }
   804 void SkPictureRecord::endRecording() {
   805     SkASSERT(kNoInitialSave != fInitialSaveCount);
   806     this->restoreToCount(fInitialSaveCount);
   807 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   808     fMCMgr.finish();
   809 #endif
   810 }
   812 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   813 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
   814     size_t offset = fWriter.bytesWritten();
   815     this->addInt(-1);
   816     return offset;
   817 }
   818 #else
   819 int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
   820     if (fRestoreOffsetStack.isEmpty()) {
   821         return -1;
   822     }
   824     // The RestoreOffset field is initially filled with a placeholder
   825     // value that points to the offset of the previous RestoreOffset
   826     // in the current stack level, thus forming a linked list so that
   827     // the restore offsets can be filled in when the corresponding
   828     // restore command is recorded.
   829     int32_t prevOffset = fRestoreOffsetStack.top();
   831     if (regionOpExpands(op)) {
   832         // Run back through any previous clip ops, and mark their offset to
   833         // be 0, disabling their ability to trigger a jump-to-restore, otherwise
   834         // they could hide this clips ability to expand the clip (i.e. go from
   835         // empty to non-empty).
   836         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
   838         // Reset the pointer back to the previous clip so that subsequent
   839         // restores don't overwrite the offsets we just cleared.
   840         prevOffset = 0;
   841     }
   843     size_t offset = fWriter.bytesWritten();
   844     this->addInt(prevOffset);
   845     fRestoreOffsetStack.top() = offset;
   846     return offset;
   847 }
   848 #endif
   850 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
   852 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   853     fMCMgr.clipRect(rect, op, doAA);
   854 #else
   855     this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
   856 #endif
   857     this->INHERITED::onClipRect(rect, op, edgeStyle);
   858 }
   860 int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
   861     // id + rect + clip params
   862     uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
   863 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   864     size += kUInt32Size;    // + restore offset
   865 #else
   866     // recordRestoreOffsetPlaceholder doesn't always write an offset
   867     if (!fRestoreOffsetStack.isEmpty()) {
   868         // + restore offset
   869         size += kUInt32Size;
   870     }
   871 #endif
   872     size_t initialOffset = this->addDraw(CLIP_RECT, &size);
   873     this->addRect(rect);
   874     this->addInt(ClipParams_pack(op, doAA));
   875     int offset = this->recordRestoreOffsetPlaceholder(op);
   877     this->validate(initialOffset, size);
   878     return offset;
   879 }
   881 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
   883 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   884     fMCMgr.clipRRect(rrect, op, doAA);
   885 #else
   886     this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
   887 #endif
   888     if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
   889         this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
   890     } else {
   891         this->INHERITED::onClipRRect(rrect, op, edgeStyle);
   892     }
   893 }
   895 int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
   896     // op + rrect + clip params
   897     uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
   898 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   899     size += kUInt32Size;    // + restore offset
   900 #else
   901     // recordRestoreOffsetPlaceholder doesn't always write an offset
   902     if (!fRestoreOffsetStack.isEmpty()) {
   903         // + restore offset
   904         size += kUInt32Size;
   905     }
   906 #endif
   907     size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
   908     this->addRRect(rrect);
   909     this->addInt(ClipParams_pack(op, doAA));
   910     int offset = recordRestoreOffsetPlaceholder(op);
   911     this->validate(initialOffset, size);
   912     return offset;
   913 }
   915 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
   917 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   918     fMCMgr.clipPath(path, op, doAA);
   919 #else
   920     int pathID = this->addPathToHeap(path);
   921     this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
   922 #endif
   924     if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
   925         this->updateClipConservativelyUsingBounds(path.getBounds(), op,
   926                                                   path.isInverseFillType());
   927     } else {
   928         this->INHERITED::onClipPath(path, op, edgeStyle);
   929     }
   930 }
   932 int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
   933     // op + path index + clip params
   934     uint32_t size = 3 * kUInt32Size;
   935 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   936     size += kUInt32Size;    // + restore offset
   937 #else
   938     // recordRestoreOffsetPlaceholder doesn't always write an offset
   939     if (!fRestoreOffsetStack.isEmpty()) {
   940         // + restore offset
   941         size += kUInt32Size;
   942     }
   943 #endif
   944     size_t initialOffset = this->addDraw(CLIP_PATH, &size);
   945     this->addInt(pathID);
   946     this->addInt(ClipParams_pack(op, doAA));
   947     int offset = recordRestoreOffsetPlaceholder(op);
   948     this->validate(initialOffset, size);
   949     return offset;
   950 }
   952 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
   954 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   955     fMCMgr.clipRegion(region, op);
   956 #else
   957     this->recordClipRegion(region, op);
   958 #endif
   959     this->INHERITED::onClipRegion(region, op);
   960 }
   962 int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
   963     // op + clip params + region
   964     uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
   965 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   966     size += kUInt32Size;    // + restore offset
   967 #else
   968     // recordRestoreOffsetPlaceholder doesn't always write an offset
   969     if (!fRestoreOffsetStack.isEmpty()) {
   970         // + restore offset
   971         size += kUInt32Size;
   972     }
   973 #endif
   974     size_t initialOffset = this->addDraw(CLIP_REGION, &size);
   975     this->addRegion(region);
   976     this->addInt(ClipParams_pack(op, false));
   977     int offset = this->recordRestoreOffsetPlaceholder(op);
   979     this->validate(initialOffset, size);
   980     return offset;
   981 }
   983 void SkPictureRecord::clear(SkColor color) {
   985 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   986     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
   987 #endif
   989     // op + color
   990     uint32_t size = 2 * kUInt32Size;
   991     size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
   992     this->addInt(color);
   993     this->validate(initialOffset, size);
   994 }
   996 void SkPictureRecord::drawPaint(const SkPaint& paint) {
   998 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   999     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1000 #endif
  1002     // op + paint index
  1003     uint32_t size = 2 * kUInt32Size;
  1004     size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
  1005     SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
  1006     this->addPaint(paint);
  1007     this->validate(initialOffset, size);
  1010 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
  1011                                  const SkPaint& paint) {
  1013 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1014     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1015 #endif
  1017     // op + paint index + mode + count + point data
  1018     uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
  1019     size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
  1020     SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
  1021     this->addPaint(paint);
  1022     this->addInt(mode);
  1023     this->addInt(count);
  1024     fWriter.writeMul4(pts, count * sizeof(SkPoint));
  1025     this->validate(initialOffset, size);
  1028 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
  1030 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1031     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1032 #endif
  1034     // op + paint index + rect
  1035     uint32_t size = 2 * kUInt32Size + sizeof(oval);
  1036     size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
  1037     SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
  1038     this->addPaint(paint);
  1039     this->addRect(oval);
  1040     this->validate(initialOffset, size);
  1043 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
  1045 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1046     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1047 #endif
  1049     // op + paint index + rect
  1050     uint32_t size = 2 * kUInt32Size + sizeof(rect);
  1051     size_t initialOffset = this->addDraw(DRAW_RECT, &size);
  1052     SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
  1053     this->addPaint(paint);
  1054     this->addRect(rect);
  1055     this->validate(initialOffset, size);
  1058 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
  1060 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1061     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1062 #endif
  1064     if (rrect.isRect()) {
  1065         this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
  1066     } else if (rrect.isOval()) {
  1067         this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
  1068     } else {
  1069         // op + paint index + rrect
  1070         uint32_t initialOffset, size;
  1071         size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
  1072         initialOffset = this->addDraw(DRAW_RRECT, &size);
  1073         SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
  1074         this->addPaint(paint);
  1075         this->addRRect(rrect);
  1076         this->validate(initialOffset, size);
  1080 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
  1081                                    const SkPaint& paint) {
  1083 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1084     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1085 #endif
  1087     // op + paint index + rrects
  1088     uint32_t initialOffset, size;
  1089     size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
  1090     initialOffset = this->addDraw(DRAW_DRRECT, &size);
  1091     SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
  1092     this->addPaint(paint);
  1093     this->addRRect(outer);
  1094     this->addRRect(inner);
  1095     this->validate(initialOffset, size);
  1098 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
  1100 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1101     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1102 #endif
  1104     // op + paint index + path index
  1105     uint32_t size = 3 * kUInt32Size;
  1106     size_t initialOffset = this->addDraw(DRAW_PATH, &size);
  1107     SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
  1108     this->addPaint(paint);
  1109     this->addPath(path);
  1110     this->validate(initialOffset, size);
  1113 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
  1114                                  const SkPaint* paint = NULL) {
  1115     if (bitmap.drawsNothing()) {
  1116         return;
  1119 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1120     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1121 #endif
  1123     // op + paint index + bitmap index + left + top
  1124     uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
  1125     size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
  1126     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
  1127     this->addPaintPtr(paint);
  1128     int bitmapID = this->addBitmap(bitmap);
  1129     this->addScalar(left);
  1130     this->addScalar(top);
  1131     this->validate(initialOffset, size);
  1132     this->trackBitmapUse(bitmapID, initialOffset);
  1135 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
  1136                                            const SkRect& dst, const SkPaint* paint,
  1137                                            DrawBitmapRectFlags flags) {
  1138     if (bitmap.drawsNothing()) {
  1139         return;
  1142 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1143     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1144 #endif
  1145     // id + paint index + bitmap index + bool for 'src' + flags
  1146     uint32_t size = 5 * kUInt32Size;
  1147     if (NULL != src) {
  1148         size += sizeof(*src);   // + rect
  1150     size += sizeof(dst);        // + rect
  1152     size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
  1153     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
  1154              == fWriter.bytesWritten());
  1155     this->addPaintPtr(paint);
  1156     int bitmapID = this->addBitmap(bitmap);
  1157     this->addRectPtr(src);  // may be null
  1158     this->addRect(dst);
  1159     this->addInt(flags);
  1160     this->validate(initialOffset, size);
  1161     this->trackBitmapUse(bitmapID, initialOffset);
  1164 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
  1165                                        const SkPaint* paint) {
  1166     if (bitmap.drawsNothing()) {
  1167         return;
  1170 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1171     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1172 #endif
  1174     // id + paint index + bitmap index + matrix
  1175     uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
  1176     size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
  1177     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
  1178     this->addPaintPtr(paint);
  1179     int bitmapID = this->addBitmap(bitmap);
  1180     this->addMatrix(matrix);
  1181     this->validate(initialOffset, size);
  1182     this->trackBitmapUse(bitmapID, initialOffset);
  1185 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
  1186                                      const SkRect& dst, const SkPaint* paint) {
  1187     if (bitmap.drawsNothing()) {
  1188         return;
  1191 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1192     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1193 #endif
  1195     // op + paint index + bitmap id + center + dst rect
  1196     uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
  1197     size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
  1198     SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
  1199     this->addPaintPtr(paint);
  1200     int bitmapID = this->addBitmap(bitmap);
  1201     this->addIRect(center);
  1202     this->addRect(dst);
  1203     this->validate(initialOffset, size);
  1204     this->trackBitmapUse(bitmapID, initialOffset);
  1207 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
  1208                                  const SkPaint* paint = NULL) {
  1209     if (bitmap.drawsNothing()) {
  1210         return;
  1213 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1214     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1215 #endif
  1217     // op + paint index + bitmap index + left + top
  1218     uint32_t size = 5 * kUInt32Size;
  1219     size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
  1220     SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
  1221     this->addPaintPtr(paint);
  1222     int bitmapID = this->addBitmap(bitmap);
  1223     this->addInt(left);
  1224     this->addInt(top);
  1225     this->validate(initialOffset, size);
  1226     this->trackBitmapUse(bitmapID, initialOffset);
  1229 void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
  1230     SkPaint::FontMetrics metrics;
  1231     paint.getFontMetrics(&metrics);
  1232     SkRect bounds;
  1233     // construct a rect so we can see any adjustments from the paint.
  1234     // we use 0,1 for left,right, just so the rect isn't empty
  1235     bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
  1236     (void)paint.computeFastBounds(bounds, &bounds);
  1237     topbot[0] = bounds.fTop;
  1238     topbot[1] = bounds.fBottom;
  1241 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
  1242                                               SkScalar minY, SkScalar maxY) {
  1243     WriteTopBot(paint, flat);
  1244     this->addScalar(flat.topBot()[0] + minY);
  1245     this->addScalar(flat.topBot()[1] + maxY);
  1248 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
  1249                       SkScalar y, const SkPaint& paint) {
  1251 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1252     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1253 #endif
  1255     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
  1257     // op + paint index + length + 'length' worth of chars + x + y
  1258     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
  1259     if (fast) {
  1260         size += 2 * sizeof(SkScalar); // + top & bottom
  1263     DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
  1264     size_t initialOffset = this->addDraw(op, &size);
  1265     SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
  1266     const SkFlatData* flatPaintData = addPaint(paint);
  1267     SkASSERT(flatPaintData);
  1268     this->addText(text, byteLength);
  1269     this->addScalar(x);
  1270     this->addScalar(y);
  1271     if (fast) {
  1272         this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
  1274     this->validate(initialOffset, size);
  1277 void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
  1278                          const SkPoint pos[], const SkPaint& paint) {
  1280 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1281     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1282 #endif
  1284     size_t points = paint.countText(text, byteLength);
  1285     if (0 == points)
  1286         return;
  1288     bool canUseDrawH = true;
  1289     SkScalar minY = pos[0].fY;
  1290     SkScalar maxY = pos[0].fY;
  1291     // check if the caller really should have used drawPosTextH()
  1293         const SkScalar firstY = pos[0].fY;
  1294         for (size_t index = 1; index < points; index++) {
  1295             if (pos[index].fY != firstY) {
  1296                 canUseDrawH = false;
  1297                 if (pos[index].fY < minY) {
  1298                     minY = pos[index].fY;
  1299                 } else if (pos[index].fY > maxY) {
  1300                     maxY = pos[index].fY;
  1306     bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
  1307     bool fast = canUseDrawH && fastBounds;
  1309     // op + paint index + length + 'length' worth of data + num points
  1310     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
  1311     if (canUseDrawH) {
  1312         if (fast) {
  1313             size += 2 * sizeof(SkScalar); // + top & bottom
  1315         // + y-pos + actual x-point data
  1316         size += sizeof(SkScalar) + points * sizeof(SkScalar);
  1317     } else {
  1318         // + x&y point data
  1319         size += points * sizeof(SkPoint);
  1320         if (fastBounds) {
  1321             size += 2 * sizeof(SkScalar); // + top & bottom
  1325     DrawType op;
  1326     if (fast) {
  1327         op = DRAW_POS_TEXT_H_TOP_BOTTOM;
  1328     } else if (canUseDrawH) {
  1329         op = DRAW_POS_TEXT_H;
  1330     } else if (fastBounds) {
  1331         op = DRAW_POS_TEXT_TOP_BOTTOM;
  1332     } else {
  1333         op = DRAW_POS_TEXT;
  1335     size_t initialOffset = this->addDraw(op, &size);
  1336     SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
  1337     const SkFlatData* flatPaintData = this->addPaint(paint);
  1338     SkASSERT(flatPaintData);
  1339     this->addText(text, byteLength);
  1340     this->addInt(points);
  1342 #ifdef SK_DEBUG_SIZE
  1343     size_t start = fWriter.bytesWritten();
  1344 #endif
  1345     if (canUseDrawH) {
  1346         if (fast) {
  1347             this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
  1349         this->addScalar(pos[0].fY);
  1350         SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
  1351         for (size_t index = 0; index < points; index++)
  1352             *xptr++ = pos[index].fX;
  1353     } else {
  1354         fWriter.writeMul4(pos, points * sizeof(SkPoint));
  1355         if (fastBounds) {
  1356             this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
  1359 #ifdef SK_DEBUG_SIZE
  1360     fPointBytes += fWriter.bytesWritten() - start;
  1361     fPointWrites += points;
  1362 #endif
  1363     this->validate(initialOffset, size);
  1366 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
  1367                           const SkScalar xpos[], SkScalar constY,
  1368                           const SkPaint& paint) {
  1370 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1371     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1372 #endif
  1374     const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
  1375     this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
  1378 void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
  1379                           const SkScalar xpos[], SkScalar constY,
  1380                           const SkPaint& paint, const SkFlatData* flatPaintData) {
  1381     size_t points = paint.countText(text, byteLength);
  1382     if (0 == points)
  1383         return;
  1385     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
  1387     // op + paint index + length + 'length' worth of data + num points
  1388     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
  1389     if (fast) {
  1390         size += 2 * sizeof(SkScalar); // + top & bottom
  1392     // + y + the actual points
  1393     size += 1 * kUInt32Size + points * sizeof(SkScalar);
  1394     size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
  1395                                          &size);
  1396     SkASSERT(flatPaintData);
  1397     this->addFlatPaint(flatPaintData);
  1399     this->addText(text, byteLength);
  1400     this->addInt(points);
  1402 #ifdef SK_DEBUG_SIZE
  1403     size_t start = fWriter.bytesWritten();
  1404 #endif
  1405     if (fast) {
  1406         this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
  1408     this->addScalar(constY);
  1409     fWriter.writeMul4(xpos, points * sizeof(SkScalar));
  1410 #ifdef SK_DEBUG_SIZE
  1411     fPointBytes += fWriter.bytesWritten() - start;
  1412     fPointWrites += points;
  1413 #endif
  1414     this->validate(initialOffset, size);
  1417 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
  1418                             const SkPath& path, const SkMatrix* matrix,
  1419                             const SkPaint& paint) {
  1421 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1422     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1423 #endif
  1425     // op + paint index + length + 'length' worth of data + path index + matrix
  1426     const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
  1427     uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
  1428     size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
  1429     SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
  1430     this->addPaint(paint);
  1431     this->addText(text, byteLength);
  1432     this->addPath(path);
  1433     this->addMatrix(m);
  1434     this->validate(initialOffset, size);
  1437 void SkPictureRecord::drawPicture(SkPicture& picture) {
  1439 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1440     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1441 #endif
  1443     // op + picture index
  1444     uint32_t size = 2 * kUInt32Size;
  1445     size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
  1446     this->addPicture(picture);
  1447     this->validate(initialOffset, size);
  1450 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
  1451                           const SkPoint vertices[], const SkPoint texs[],
  1452                           const SkColor colors[], SkXfermode* xfer,
  1453                           const uint16_t indices[], int indexCount,
  1454                           const SkPaint& paint) {
  1456 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1457     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1458 #endif
  1460     uint32_t flags = 0;
  1461     if (texs) {
  1462         flags |= DRAW_VERTICES_HAS_TEXS;
  1464     if (colors) {
  1465         flags |= DRAW_VERTICES_HAS_COLORS;
  1467     if (indexCount > 0) {
  1468         flags |= DRAW_VERTICES_HAS_INDICES;
  1470     if (NULL != xfer) {
  1471         SkXfermode::Mode mode;
  1472         if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
  1473             flags |= DRAW_VERTICES_HAS_XFER;
  1477     // op + paint index + flags + vmode + vCount + vertices
  1478     uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
  1479     if (flags & DRAW_VERTICES_HAS_TEXS) {
  1480         size += vertexCount * sizeof(SkPoint);  // + uvs
  1482     if (flags & DRAW_VERTICES_HAS_COLORS) {
  1483         size += vertexCount * sizeof(SkColor);  // + vert colors
  1485     if (flags & DRAW_VERTICES_HAS_INDICES) {
  1486         // + num indices + indices
  1487         size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
  1489     if (flags & DRAW_VERTICES_HAS_XFER) {
  1490         size += kUInt32Size;    // mode enum
  1493     size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
  1494     SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
  1495     this->addPaint(paint);
  1496     this->addInt(flags);
  1497     this->addInt(vmode);
  1498     this->addInt(vertexCount);
  1499     this->addPoints(vertices, vertexCount);
  1500     if (flags & DRAW_VERTICES_HAS_TEXS) {
  1501         this->addPoints(texs, vertexCount);
  1503     if (flags & DRAW_VERTICES_HAS_COLORS) {
  1504         fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
  1506     if (flags & DRAW_VERTICES_HAS_INDICES) {
  1507         this->addInt(indexCount);
  1508         fWriter.writePad(indices, indexCount * sizeof(uint16_t));
  1510     if (flags & DRAW_VERTICES_HAS_XFER) {
  1511         SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
  1512         (void)xfer->asMode(&mode);
  1513         this->addInt(mode);
  1515     this->validate(initialOffset, size);
  1518 void SkPictureRecord::drawData(const void* data, size_t length) {
  1520 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1521     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1522 #endif
  1524     // op + length + 'length' worth of data
  1525     uint32_t size = 2 * kUInt32Size + SkAlign4(length);
  1526     size_t initialOffset = this->addDraw(DRAW_DATA, &size);
  1527     this->addInt(length);
  1528     fWriter.writePad(data, length);
  1529     this->validate(initialOffset, size);
  1532 void SkPictureRecord::beginCommentGroup(const char* description) {
  1533     // op/size + length of string + \0 terminated chars
  1534     int length = strlen(description);
  1535     uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
  1536     size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
  1537     fWriter.writeString(description, length);
  1538     this->validate(initialOffset, size);
  1541 void SkPictureRecord::addComment(const char* kywd, const char* value) {
  1542     // op/size + 2x length of string + 2x \0 terminated chars
  1543     int kywdLen = strlen(kywd);
  1544     int valueLen = strlen(value);
  1545     uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
  1546     size_t initialOffset = this->addDraw(COMMENT, &size);
  1547     fWriter.writeString(kywd, kywdLen);
  1548     fWriter.writeString(value, valueLen);
  1549     this->validate(initialOffset, size);
  1552 void SkPictureRecord::endCommentGroup() {
  1553     // op/size
  1554     uint32_t size = 1 * kUInt32Size;
  1555     size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
  1556     this->validate(initialOffset, size);
  1559 // [op/size] [rect] [skip offset]
  1560 static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
  1561 void SkPictureRecord::onPushCull(const SkRect& cullRect) {
  1562     // Skip identical cull rects.
  1563     if (!fCullOffsetStack.isEmpty()) {
  1564         const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect));
  1565         if (prevCull == cullRect) {
  1566             // Skipped culls are tracked on the stack, but they point to the previous offset.
  1567             fCullOffsetStack.push(fCullOffsetStack.top());
  1568             return;
  1571         SkASSERT(prevCull.contains(cullRect));
  1574     uint32_t size = kPushCullOpSize;
  1575     size_t initialOffset = this->addDraw(PUSH_CULL, &size);
  1576     // PUSH_CULL's size should stay constant (used to rewind).
  1577     SkASSERT(size == kPushCullOpSize);
  1579     this->addRect(cullRect);
  1580     fCullOffsetStack.push(fWriter.bytesWritten());
  1581     this->addInt(0);
  1582     this->validate(initialOffset, size);
  1585 void SkPictureRecord::onPopCull() {
  1586     SkASSERT(!fCullOffsetStack.isEmpty());
  1588     uint32_t cullSkipOffset = fCullOffsetStack.top();
  1589     fCullOffsetStack.pop();
  1591     // Skipped push, do the same for pop.
  1592     if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) {
  1593         return;
  1596     // Collapse empty push/pop pairs.
  1597     if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
  1598         SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
  1599         SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
  1600         fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
  1601         return;
  1604     // op only
  1605     uint32_t size = kUInt32Size;
  1606     size_t initialOffset = this->addDraw(POP_CULL, &size);
  1608     // update the cull skip offset to point past this op.
  1609     fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
  1611     this->validate(initialOffset, size);
  1614 ///////////////////////////////////////////////////////////////////////////////
  1616 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
  1617     return SkSurface::NewPicture(info.fWidth, info.fHeight);
  1620 void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) {
  1621 #ifndef SK_ALLOW_BITMAP_TRACKING
  1622     return;
  1623 #endif
  1625     if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) {
  1626         return;
  1629     if (SkBitmapHeap::INVALID_SLOT == bitmapID) {
  1630         return;
  1633     if (NULL == fBitmapUseOffsets) {
  1634         fBitmapUseOffsets.reset(SkNEW(SkOffsetTable));
  1637     fBitmapUseOffsets->add(bitmapID, offset);
  1640 int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
  1641     const int index = fBitmapHeap->insert(bitmap);
  1642     // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
  1643     // release builds, the invalid value will be recorded so that the reader will know that there
  1644     // was a problem.
  1645     SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
  1646     this->addInt(index);
  1647     return index;
  1650 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
  1651     fWriter.writeMatrix(matrix);
  1654 const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
  1655     return fPaints.findAndReturnFlat(paint);
  1658 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
  1659     const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
  1660     this->addFlatPaint(data);
  1661     return data;
  1664 void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
  1665     int index = flatPaint ? flatPaint->index() : 0;
  1666     this->addInt(index);
  1669 int SkPictureRecord::addPathToHeap(const SkPath& path) {
  1670     if (NULL == fPathHeap) {
  1671         fPathHeap = SkNEW(SkPathHeap);
  1673 #ifdef SK_DEDUP_PICTURE_PATHS
  1674     return fPathHeap->insert(path);
  1675 #else
  1676     return fPathHeap->append(path);
  1677 #endif
  1680 void SkPictureRecord::addPath(const SkPath& path) {
  1681     this->addInt(this->addPathToHeap(path));
  1684 void SkPictureRecord::addPicture(SkPicture& picture) {
  1685     int index = fPictureRefs.find(&picture);
  1686     if (index < 0) {    // not found
  1687         index = fPictureRefs.count();
  1688         *fPictureRefs.append() = &picture;
  1689         picture.ref();
  1691     // follow the convention of recording a 1-based index
  1692     this->addInt(index + 1);
  1695 void SkPictureRecord::addPoint(const SkPoint& point) {
  1696 #ifdef SK_DEBUG_SIZE
  1697     size_t start = fWriter.bytesWritten();
  1698 #endif
  1699     fWriter.writePoint(point);
  1700 #ifdef SK_DEBUG_SIZE
  1701     fPointBytes += fWriter.bytesWritten() - start;
  1702     fPointWrites++;
  1703 #endif
  1706 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
  1707     fWriter.writeMul4(pts, count * sizeof(SkPoint));
  1708 #ifdef SK_DEBUG_SIZE
  1709     fPointBytes += count * sizeof(SkPoint);
  1710     fPointWrites++;
  1711 #endif
  1714 void SkPictureRecord::addRect(const SkRect& rect) {
  1715 #ifdef SK_DEBUG_SIZE
  1716     size_t start = fWriter.bytesWritten();
  1717 #endif
  1718     fWriter.writeRect(rect);
  1719 #ifdef SK_DEBUG_SIZE
  1720     fRectBytes += fWriter.bytesWritten() - start;
  1721     fRectWrites++;
  1722 #endif
  1725 void SkPictureRecord::addRectPtr(const SkRect* rect) {
  1726     if (fWriter.writeBool(rect != NULL)) {
  1727         fWriter.writeRect(*rect);
  1731 void SkPictureRecord::addIRect(const SkIRect& rect) {
  1732     fWriter.write(&rect, sizeof(rect));
  1735 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
  1736     if (fWriter.writeBool(rect != NULL)) {
  1737         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
  1741 void SkPictureRecord::addRRect(const SkRRect& rrect) {
  1742     fWriter.writeRRect(rrect);
  1745 void SkPictureRecord::addRegion(const SkRegion& region) {
  1746     fWriter.writeRegion(region);
  1749 void SkPictureRecord::addText(const void* text, size_t byteLength) {
  1750 #ifdef SK_DEBUG_SIZE
  1751     size_t start = fWriter.bytesWritten();
  1752 #endif
  1753     addInt(byteLength);
  1754     fWriter.writePad(text, byteLength);
  1755 #ifdef SK_DEBUG_SIZE
  1756     fTextBytes += fWriter.bytesWritten() - start;
  1757     fTextWrites++;
  1758 #endif
  1761 ///////////////////////////////////////////////////////////////////////////////
  1763 #ifdef SK_DEBUG_SIZE
  1764 size_t SkPictureRecord::size() const {
  1765     size_t result = 0;
  1766     size_t sizeData;
  1767     bitmaps(&sizeData);
  1768     result += sizeData;
  1769     matrices(&sizeData);
  1770     result += sizeData;
  1771     paints(&sizeData);
  1772     result += sizeData;
  1773     paths(&sizeData);
  1774     result += sizeData;
  1775     pictures(&sizeData);
  1776     result += sizeData;
  1777     regions(&sizeData);
  1778     result += sizeData;
  1779     result += streamlen();
  1780     return result;
  1783 int SkPictureRecord::bitmaps(size_t* size) const {
  1784     size_t result = 0;
  1785     int count = fBitmaps.count();
  1786     for (int index = 0; index < count; index++)
  1787         result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
  1788     *size = result;
  1789     return count;
  1792 int SkPictureRecord::matrices(size_t* size) const {
  1793     int count = fMatrices.count();
  1794     *size = sizeof(fMatrices[0]) * count;
  1795     return count;
  1798 int SkPictureRecord::paints(size_t* size) const {
  1799     size_t result = 0;
  1800     int count = fPaints.count();
  1801     for (int index = 0; index < count; index++)
  1802         result += sizeof(fPaints[index]) + fPaints[index]->size();
  1803     *size = result;
  1804     return count;
  1807 int SkPictureRecord::paths(size_t* size) const {
  1808     size_t result = 0;
  1809     int count = fPaths.count();
  1810     for (int index = 0; index < count; index++)
  1811         result += sizeof(fPaths[index]) + fPaths[index]->size();
  1812     *size = result;
  1813     return count;
  1816 int SkPictureRecord::regions(size_t* size) const {
  1817     size_t result = 0;
  1818     int count = fRegions.count();
  1819     for (int index = 0; index < count; index++)
  1820         result += sizeof(fRegions[index]) + fRegions[index]->size();
  1821     *size = result;
  1822     return count;
  1825 size_t SkPictureRecord::streamlen() const {
  1826     return fWriter.size();
  1828 #endif
  1830 #ifdef SK_DEBUG_VALIDATE
  1831 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
  1832     SkASSERT(fWriter.size() == initialOffset + size);
  1834     validateBitmaps();
  1835     validateMatrices();
  1836     validatePaints();
  1837     validatePaths();
  1838     validateRegions();
  1841 void SkPictureRecord::validateBitmaps() const {
  1842     int count = fBitmapHeap->count();
  1843     SkASSERT((unsigned) count < 0x1000);
  1844     for (int index = 0; index < count; index++) {
  1845         const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
  1846         SkASSERT(bitPtr);
  1847         bitPtr->validate();
  1851 void SkPictureRecord::validateMatrices() const {
  1852     int count = fMatrices.count();
  1853     SkASSERT((unsigned) count < 0x1000);
  1854     for (int index = 0; index < count; index++) {
  1855         const SkFlatData* matrix = fMatrices[index];
  1856         SkASSERT(matrix);
  1857 //        matrix->validate();
  1861 void SkPictureRecord::validatePaints() const {
  1862     int count = fPaints.count();
  1863     SkASSERT((unsigned) count < 0x1000);
  1864     for (int index = 0; index < count; index++) {
  1865         const SkFlatData* paint = fPaints[index];
  1866         SkASSERT(paint);
  1867 //            paint->validate();
  1871 void SkPictureRecord::validatePaths() const {
  1872     if (NULL == fPathHeap) {
  1873         return;
  1876     int count = fPathHeap->count();
  1877     SkASSERT((unsigned) count < 0x1000);
  1878     for (int index = 0; index < count; index++) {
  1879         const SkPath& path = (*fPathHeap)[index];
  1880         path.validate();
  1884 void SkPictureRecord::validateRegions() const {
  1885     int count = fRegions.count();
  1886     SkASSERT((unsigned) count < 0x1000);
  1887     for (int index = 0; index < count; index++) {
  1888         const SkFlatData* region = fRegions[index];
  1889         SkASSERT(region);
  1890 //        region->validate();
  1893 #endif

mercurial