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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkPictureRecord.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1893 @@
     1.4 +/*
     1.5 + * Copyright 2011 Google Inc.
     1.6 + *
     1.7 + * Use of this source code is governed by a BSD-style license that can be
     1.8 + * found in the LICENSE file.
     1.9 + */
    1.10 +
    1.11 +#include "SkPictureRecord.h"
    1.12 +#include "SkTSearch.h"
    1.13 +#include "SkPixelRef.h"
    1.14 +#include "SkRRect.h"
    1.15 +#include "SkBBoxHierarchy.h"
    1.16 +#include "SkDevice.h"
    1.17 +#include "SkOffsetTable.h"
    1.18 +#include "SkPictureStateTree.h"
    1.19 +#include "SkSurface.h"
    1.20 +
    1.21 +#define HEAP_BLOCK_SIZE 4096
    1.22 +
    1.23 +enum {
    1.24 +    // just need a value that save or getSaveCount would never return
    1.25 +    kNoInitialSave = -1,
    1.26 +};
    1.27 +
    1.28 +// A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
    1.29 +static int const kUInt32Size = 4;
    1.30 +
    1.31 +static const uint32_t kSaveSize = 2 * kUInt32Size;
    1.32 +static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
    1.33 +static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
    1.34 +
    1.35 +SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
    1.36 +    : INHERITED(dimensions.width(), dimensions.height())
    1.37 +    , fBoundingHierarchy(NULL)
    1.38 +    , fStateTree(NULL)
    1.39 +    , fFlattenableHeap(HEAP_BLOCK_SIZE)
    1.40 +    , fPaints(&fFlattenableHeap)
    1.41 +    , fRecordFlags(flags)
    1.42 +    , fOptsEnabled(true) {
    1.43 +#ifdef SK_DEBUG_SIZE
    1.44 +    fPointBytes = fRectBytes = fTextBytes = 0;
    1.45 +    fPointWrites = fRectWrites = fTextWrites = 0;
    1.46 +#endif
    1.47 +
    1.48 +    fBitmapHeap = SkNEW(SkBitmapHeap);
    1.49 +    fFlattenableHeap.setBitmapStorage(fBitmapHeap);
    1.50 +    fPathHeap = NULL;   // lazy allocate
    1.51 +
    1.52 +#ifndef SK_COLLAPSE_MATRIX_CLIP_STATE
    1.53 +    fFirstSavedLayerIndex = kNoSavedLayerIndex;
    1.54 +#endif
    1.55 +
    1.56 +    fInitialSaveCount = kNoInitialSave;
    1.57 +
    1.58 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
    1.59 +    fMCMgr.init(this);
    1.60 +#endif
    1.61 +}
    1.62 +
    1.63 +SkPictureRecord::~SkPictureRecord() {
    1.64 +    SkSafeUnref(fBitmapHeap);
    1.65 +    SkSafeUnref(fPathHeap);
    1.66 +    SkSafeUnref(fBoundingHierarchy);
    1.67 +    SkSafeUnref(fStateTree);
    1.68 +    fFlattenableHeap.setBitmapStorage(NULL);
    1.69 +    fPictureRefs.unrefAll();
    1.70 +}
    1.71 +
    1.72 +///////////////////////////////////////////////////////////////////////////////
    1.73 +
    1.74 +// Return the offset of the paint inside a given op's byte stream. A zero
    1.75 +// return value means there is no paint (and you really shouldn't be calling
    1.76 +// this method)
    1.77 +static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) {
    1.78 +    // These offsets are where the paint would be if the op size doesn't overflow
    1.79 +    static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = {
    1.80 +        0,  // UNUSED - no paint
    1.81 +        0,  // CLIP_PATH - no paint
    1.82 +        0,  // CLIP_REGION - no paint
    1.83 +        0,  // CLIP_RECT - no paint
    1.84 +        0,  // CLIP_RRECT - no paint
    1.85 +        0,  // CONCAT - no paint
    1.86 +        1,  // DRAW_BITMAP - right after op code
    1.87 +        1,  // DRAW_BITMAP_MATRIX - right after op code
    1.88 +        1,  // DRAW_BITMAP_NINE - right after op code
    1.89 +        1,  // DRAW_BITMAP_RECT_TO_RECT - right after op code
    1.90 +        0,  // DRAW_CLEAR - no paint
    1.91 +        0,  // DRAW_DATA - no paint
    1.92 +        1,  // DRAW_OVAL - right after op code
    1.93 +        1,  // DRAW_PAINT - right after op code
    1.94 +        1,  // DRAW_PATH - right after op code
    1.95 +        0,  // DRAW_PICTURE - no paint
    1.96 +        1,  // DRAW_POINTS - right after op code
    1.97 +        1,  // DRAW_POS_TEXT - right after op code
    1.98 +        1,  // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
    1.99 +        1,  // DRAW_POS_TEXT_H - right after op code
   1.100 +        1,  // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
   1.101 +        1,  // DRAW_RECT - right after op code
   1.102 +        1,  // DRAW_RRECT - right after op code
   1.103 +        1,  // DRAW_SPRITE - right after op code
   1.104 +        1,  // DRAW_TEXT - right after op code
   1.105 +        1,  // DRAW_TEXT_ON_PATH - right after op code
   1.106 +        1,  // DRAW_TEXT_TOP_BOTTOM - right after op code
   1.107 +        1,  // DRAW_VERTICES - right after op code
   1.108 +        0,  // RESTORE - no paint
   1.109 +        0,  // ROTATE - no paint
   1.110 +        0,  // SAVE - no paint
   1.111 +        0,  // SAVE_LAYER - see below - this paint's location varies
   1.112 +        0,  // SCALE - no paint
   1.113 +        0,  // SET_MATRIX - no paint
   1.114 +        0,  // SKEW - no paint
   1.115 +        0,  // TRANSLATE - no paint
   1.116 +        0,  // NOOP - no paint
   1.117 +        0,  // BEGIN_GROUP - no paint
   1.118 +        0,  // COMMENT - no paint
   1.119 +        0,  // END_GROUP - no paint
   1.120 +        1,  // DRAWDRRECT - right after op code
   1.121 +        0,  // PUSH_CULL - no paint
   1.122 +        0,  // POP_CULL - no paint
   1.123 +    };
   1.124 +
   1.125 +    SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
   1.126 +                      need_to_be_in_sync);
   1.127 +    SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
   1.128 +
   1.129 +    int overflow = 0;
   1.130 +    if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
   1.131 +        // This op's size overflows so an extra uint32_t will be written
   1.132 +        // after the op code
   1.133 +        overflow = sizeof(uint32_t);
   1.134 +    }
   1.135 +
   1.136 +    if (SAVE_LAYER == op) {
   1.137 +        static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
   1.138 +        static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
   1.139 +
   1.140 +        if (kSaveLayerNoBoundsSize == opSize) {
   1.141 +            return kSaveLayerNoBoundsPaintOffset + overflow;
   1.142 +        } else {
   1.143 +            SkASSERT(kSaveLayerWithBoundsSize == opSize);
   1.144 +            return kSaveLayerWithBoundsPaintOffset + overflow;
   1.145 +        }
   1.146 +    }
   1.147 +
   1.148 +    SkASSERT(0 != gPaintOffsets[op]);   // really shouldn't be calling this method
   1.149 +    return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
   1.150 +}
   1.151 +
   1.152 +void SkPictureRecord::willSave(SaveFlags flags) {
   1.153 +
   1.154 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.155 +    fMCMgr.save(flags);
   1.156 +#else
   1.157 +    // record the offset to us, making it non-positive to distinguish a save
   1.158 +    // from a clip entry.
   1.159 +    fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
   1.160 +    this->recordSave(flags);
   1.161 +#endif
   1.162 +
   1.163 +    this->INHERITED::willSave(flags);
   1.164 +}
   1.165 +
   1.166 +void SkPictureRecord::recordSave(SaveFlags flags) {
   1.167 +    // op + flags
   1.168 +    uint32_t size = kSaveSize;
   1.169 +    size_t initialOffset = this->addDraw(SAVE, &size);
   1.170 +    this->addInt(flags);
   1.171 +
   1.172 +    this->validate(initialOffset, size);
   1.173 +}
   1.174 +
   1.175 +SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
   1.176 +                                                           const SkPaint* paint, SaveFlags flags) {
   1.177 +
   1.178 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.179 +    fMCMgr.saveLayer(bounds, paint, flags);
   1.180 +#else
   1.181 +    // record the offset to us, making it non-positive to distinguish a save
   1.182 +    // from a clip entry.
   1.183 +    fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
   1.184 +    this->recordSaveLayer(bounds, paint, flags);
   1.185 +    if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
   1.186 +        fFirstSavedLayerIndex = fRestoreOffsetStack.count();
   1.187 +    }
   1.188 +#endif
   1.189 +
   1.190 +    this->INHERITED::willSaveLayer(bounds, paint, flags);
   1.191 +    /*  No need for a (potentially very big) layer which we don't actually need
   1.192 +        at this time (and may not be able to afford since during record our
   1.193 +        clip starts out the size of the picture, which is often much larger
   1.194 +        than the size of the actual device we'll use during playback).
   1.195 +     */
   1.196 +    return kNoLayer_SaveLayerStrategy;
   1.197 +}
   1.198 +
   1.199 +void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
   1.200 +                                      SaveFlags flags) {
   1.201 +    // op + bool for 'bounds'
   1.202 +    uint32_t size = 2 * kUInt32Size;
   1.203 +    if (NULL != bounds) {
   1.204 +        size += sizeof(*bounds); // + rect
   1.205 +    }
   1.206 +    // + paint index + flags
   1.207 +    size += 2 * kUInt32Size;
   1.208 +
   1.209 +    SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
   1.210 +
   1.211 +    size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
   1.212 +    this->addRectPtr(bounds);
   1.213 +    SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.bytesWritten());
   1.214 +    this->addPaintPtr(paint);
   1.215 +    this->addInt(flags);
   1.216 +
   1.217 +    this->validate(initialOffset, size);
   1.218 +}
   1.219 +
   1.220 +bool SkPictureRecord::isDrawingToLayer() const {
   1.221 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.222 +    return fMCMgr.isDrawingToLayer();
   1.223 +#else
   1.224 +    return fFirstSavedLayerIndex != kNoSavedLayerIndex;
   1.225 +#endif
   1.226 +}
   1.227 +
   1.228 +/*
   1.229 + * Read the op code from 'offset' in 'writer'.
   1.230 + */
   1.231 +#ifdef SK_DEBUG
   1.232 +static DrawType peek_op(SkWriter32* writer, int32_t offset) {
   1.233 +    return (DrawType)(writer->readTAt<uint32_t>(offset) >> 24);
   1.234 +}
   1.235 +#endif
   1.236 +
   1.237 +/*
   1.238 + * Read the op code from 'offset' in 'writer' and extract the size too.
   1.239 + */
   1.240 +static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) {
   1.241 +    uint32_t peek = writer->readTAt<uint32_t>(offset);
   1.242 +
   1.243 +    uint32_t op;
   1.244 +    UNPACK_8_24(peek, op, *size);
   1.245 +    if (MASK_24 == *size) {
   1.246 +        // size required its own slot right after the op code
   1.247 +        *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
   1.248 +    }
   1.249 +    return (DrawType) op;
   1.250 +}
   1.251 +
   1.252 +#ifdef TRACK_COLLAPSE_STATS
   1.253 +    static int gCollapseCount, gCollapseCalls;
   1.254 +#endif
   1.255 +
   1.256 +// Is the supplied paint simply a color?
   1.257 +static bool is_simple(const SkPaint& p) {
   1.258 +    intptr_t orAccum = (intptr_t)p.getPathEffect()  |
   1.259 +                       (intptr_t)p.getShader()      |
   1.260 +                       (intptr_t)p.getXfermode()    |
   1.261 +                       (intptr_t)p.getMaskFilter()  |
   1.262 +                       (intptr_t)p.getColorFilter() |
   1.263 +                       (intptr_t)p.getRasterizer()  |
   1.264 +                       (intptr_t)p.getLooper()      |
   1.265 +                       (intptr_t)p.getImageFilter();
   1.266 +    return 0 == orAccum;
   1.267 +}
   1.268 +
   1.269 +// CommandInfos are fed to the 'match' method and filled in with command
   1.270 +// information.
   1.271 +struct CommandInfo {
   1.272 +    DrawType fActualOp;
   1.273 +    uint32_t fOffset;
   1.274 +    uint32_t fSize;
   1.275 +};
   1.276 +
   1.277 +/*
   1.278 + * Attempt to match the provided pattern of commands starting at 'offset'
   1.279 + * in the byte stream and stopping at the end of the stream. Upon success,
   1.280 + * return true with all the pattern information filled out in the result
   1.281 + * array (i.e., actual ops, offsets and sizes).
   1.282 + * Note this method skips any NOOPs seen in the stream
   1.283 + */
   1.284 +static bool match(SkWriter32* writer, uint32_t offset,
   1.285 +                  int* pattern, CommandInfo* result, int numCommands) {
   1.286 +    SkASSERT(offset < writer->bytesWritten());
   1.287 +
   1.288 +    uint32_t curOffset = offset;
   1.289 +    uint32_t curSize = 0;
   1.290 +    int numMatched;
   1.291 +    for (numMatched = 0; numMatched < numCommands && curOffset < writer->bytesWritten(); ++numMatched) {
   1.292 +        DrawType op = peek_op_and_size(writer, curOffset, &curSize);
   1.293 +        while (NOOP == op && curOffset < writer->bytesWritten()) {
   1.294 +            curOffset += curSize;
   1.295 +            op = peek_op_and_size(writer, curOffset, &curSize);
   1.296 +        }
   1.297 +
   1.298 +        if (curOffset >= writer->bytesWritten()) {
   1.299 +            return false; // ran out of byte stream
   1.300 +        }
   1.301 +
   1.302 +        if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) {
   1.303 +            if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op &&
   1.304 +                DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) {
   1.305 +                return false;
   1.306 +            }
   1.307 +        } else if (op != pattern[numMatched]) {
   1.308 +            return false;
   1.309 +        }
   1.310 +
   1.311 +        result[numMatched].fActualOp = op;
   1.312 +        result[numMatched].fOffset = curOffset;
   1.313 +        result[numMatched].fSize = curSize;
   1.314 +
   1.315 +        curOffset += curSize;
   1.316 +    }
   1.317 +
   1.318 +    if (numMatched != numCommands) {
   1.319 +        return false;
   1.320 +    }
   1.321 +
   1.322 +    curOffset += curSize;
   1.323 +    if (curOffset < writer->bytesWritten()) {
   1.324 +        // Something else between the last command and the end of the stream
   1.325 +        return false;
   1.326 +    }
   1.327 +
   1.328 +    return true;
   1.329 +}
   1.330 +
   1.331 +// temporarily here to make code review easier
   1.332 +static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
   1.333 +                                                 SkPaintDictionary* paintDict,
   1.334 +                                                 const CommandInfo& saveLayerInfo,
   1.335 +                                                 const CommandInfo& dbmInfo);
   1.336 +
   1.337 +/*
   1.338 + * Restore has just been called (but not recorded), look back at the
   1.339 + * matching save* and see if we are in the configuration:
   1.340 + *   SAVE_LAYER
   1.341 + *       DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
   1.342 + *   RESTORE
   1.343 + * where the saveLayer's color can be moved into the drawBitmap*'s paint
   1.344 + */
   1.345 +static bool remove_save_layer1(SkWriter32* writer, int32_t offset,
   1.346 +                               SkPaintDictionary* paintDict) {
   1.347 +    // back up to the save block
   1.348 +    // TODO: add a stack to track save*/restore offsets rather than searching backwards
   1.349 +    while (offset > 0) {
   1.350 +        offset = writer->readTAt<uint32_t>(offset);
   1.351 +    }
   1.352 +
   1.353 +    int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ };
   1.354 +    CommandInfo result[SK_ARRAY_COUNT(pattern)];
   1.355 +
   1.356 +    if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
   1.357 +        return false;
   1.358 +    }
   1.359 +
   1.360 +    if (kSaveLayerWithBoundsSize == result[0].fSize) {
   1.361 +        // The saveLayer's bound can offset where the dbm is drawn
   1.362 +        return false;
   1.363 +    }
   1.364 +
   1.365 +    return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
   1.366 +                                                result[0], result[1]);
   1.367 +}
   1.368 +
   1.369 +/*
   1.370 + * Convert the command code located at 'offset' to a NOOP. Leave the size
   1.371 + * field alone so the NOOP can be skipped later.
   1.372 + */
   1.373 +static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) {
   1.374 +    uint32_t command = writer->readTAt<uint32_t>(offset);
   1.375 +    writer->overwriteTAt(offset, (command & MASK_24) | (NOOP << 24));
   1.376 +}
   1.377 +
   1.378 +/*
   1.379 + * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint.
   1.380 + * Return true on success; false otherwise.
   1.381 + */
   1.382 +static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer,
   1.383 +                                                 SkPaintDictionary* paintDict,
   1.384 +                                                 const CommandInfo& saveLayerInfo,
   1.385 +                                                 const CommandInfo& dbmInfo) {
   1.386 +    SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp);
   1.387 +    SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp ||
   1.388 +             DRAW_BITMAP_MATRIX == dbmInfo.fActualOp ||
   1.389 +             DRAW_BITMAP_NINE == dbmInfo.fActualOp ||
   1.390 +             DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp);
   1.391 +
   1.392 +    uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize);
   1.393 +    uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize);
   1.394 +
   1.395 +    // we have a match, now we need to get the paints involved
   1.396 +    uint32_t dbmPaintId = writer->readTAt<uint32_t>(dbmInfo.fOffset + dbmPaintOffset);
   1.397 +    uint32_t saveLayerPaintId = writer->readTAt<uint32_t>(saveLayerInfo.fOffset + slPaintOffset);
   1.398 +
   1.399 +    if (0 == saveLayerPaintId) {
   1.400 +        // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer
   1.401 +        // and signal the caller (by returning true) to not add the RESTORE op
   1.402 +        convert_command_to_noop(writer, saveLayerInfo.fOffset);
   1.403 +        return true;
   1.404 +    }
   1.405 +
   1.406 +    if (0 == dbmPaintId) {
   1.407 +        // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer
   1.408 +        // and signal the caller (by returning true) to not add the RESTORE op
   1.409 +        convert_command_to_noop(writer, saveLayerInfo.fOffset);
   1.410 +        writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, saveLayerPaintId);
   1.411 +        return true;
   1.412 +    }
   1.413 +
   1.414 +    SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId));
   1.415 +    if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) {
   1.416 +        return false;
   1.417 +    }
   1.418 +
   1.419 +    // For this optimization we only fold the saveLayer and drawBitmapRect
   1.420 +    // together if the saveLayer's draw is simple (i.e., no fancy effects) and
   1.421 +    // and the only difference in the colors is that the saveLayer's can have
   1.422 +    // an alpha while the drawBitmapRect's is opaque.
   1.423 +    // TODO: it should be possible to fold them together even if they both
   1.424 +    // have different non-255 alphas
   1.425 +    SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque
   1.426 +
   1.427 +    SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId));
   1.428 +    if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) {
   1.429 +        return false;
   1.430 +    }
   1.431 +
   1.432 +    SkColor newColor = SkColorSetA(dbmPaint->getColor(),
   1.433 +                                   SkColorGetA(saveLayerPaint->getColor()));
   1.434 +    dbmPaint->setColor(newColor);
   1.435 +
   1.436 +    const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint);
   1.437 +    if (NULL == data) {
   1.438 +        return false;
   1.439 +    }
   1.440 +
   1.441 +    // kill the saveLayer and alter the DBMR2R's paint to be the modified one
   1.442 +    convert_command_to_noop(writer, saveLayerInfo.fOffset);
   1.443 +    writer->overwriteTAt(dbmInfo.fOffset + dbmPaintOffset, data->index());
   1.444 +    return true;
   1.445 +}
   1.446 +
   1.447 +/*
   1.448 + * Restore has just been called (but not recorded), look back at the
   1.449 + * matching save* and see if we are in the configuration:
   1.450 + *   SAVE_LAYER (with NULL == bounds)
   1.451 + *      SAVE
   1.452 + *         CLIP_RECT
   1.453 + *         DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT
   1.454 + *      RESTORE
   1.455 + *   RESTORE
   1.456 + * where the saveLayer's color can be moved into the drawBitmap*'s paint
   1.457 + */
   1.458 +static bool remove_save_layer2(SkWriter32* writer, int32_t offset,
   1.459 +                               SkPaintDictionary* paintDict) {
   1.460 +
   1.461 +    // back up to the save block
   1.462 +    // TODO: add a stack to track save*/restore offsets rather than searching backwards
   1.463 +    while (offset > 0) {
   1.464 +        offset = writer->readTAt<uint32_t>(offset);
   1.465 +    }
   1.466 +
   1.467 +    int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ };
   1.468 +    CommandInfo result[SK_ARRAY_COUNT(pattern)];
   1.469 +
   1.470 +    if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) {
   1.471 +        return false;
   1.472 +    }
   1.473 +
   1.474 +    if (kSaveLayerWithBoundsSize == result[0].fSize) {
   1.475 +        // The saveLayer's bound can offset where the dbm is drawn
   1.476 +        return false;
   1.477 +    }
   1.478 +
   1.479 +    return merge_savelayer_paint_into_drawbitmp(writer, paintDict,
   1.480 +                                                result[0], result[3]);
   1.481 +}
   1.482 +
   1.483 +static bool is_drawing_op(DrawType op) {
   1.484 +    return (op > CONCAT && op < ROTATE) || DRAW_DRRECT == op;
   1.485 +}
   1.486 +
   1.487 +/*
   1.488 + *  Restore has just been called (but not recorded), so look back at the
   1.489 + *  matching save(), and see if we can eliminate the pair of them, due to no
   1.490 + *  intervening matrix/clip calls.
   1.491 + *
   1.492 + *  If so, update the writer and return true, in which case we won't even record
   1.493 + *  the restore() call. If we still need the restore(), return false.
   1.494 + */
   1.495 +static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset,
   1.496 +                                       SkPaintDictionary* paintDict) {
   1.497 +#ifdef TRACK_COLLAPSE_STATS
   1.498 +    gCollapseCalls += 1;
   1.499 +#endif
   1.500 +
   1.501 +    int32_t restoreOffset = (int32_t)writer->bytesWritten();
   1.502 +
   1.503 +    // back up to the save block
   1.504 +    while (offset > 0) {
   1.505 +        offset = writer->readTAt<uint32_t>(offset);
   1.506 +    }
   1.507 +
   1.508 +    // now offset points to a save
   1.509 +    offset = -offset;
   1.510 +    uint32_t opSize;
   1.511 +    DrawType op = peek_op_and_size(writer, offset, &opSize);
   1.512 +    if (SAVE_LAYER == op) {
   1.513 +        // not ready to cull these out yet (mrr)
   1.514 +        return false;
   1.515 +    }
   1.516 +    SkASSERT(SAVE == op);
   1.517 +    SkASSERT(kSaveSize == opSize);
   1.518 +
   1.519 +    // get the save flag (last 4-bytes of the space allocated for the opSize)
   1.520 +    SkCanvas::SaveFlags saveFlags = (SkCanvas::SaveFlags) writer->readTAt<uint32_t>(offset + 4);
   1.521 +    if (SkCanvas::kMatrixClip_SaveFlag != saveFlags) {
   1.522 +        // This function's optimization is only correct for kMatrixClip style saves.
   1.523 +        // TODO: set checkMatrix & checkClip booleans here and then check for the
   1.524 +        // offending operations in the following loop.
   1.525 +        return false;
   1.526 +    }
   1.527 +
   1.528 +    // Walk forward until we get back to either a draw-verb (abort) or we hit
   1.529 +    // our restore (success).
   1.530 +    int32_t saveOffset = offset;
   1.531 +
   1.532 +    offset += opSize;
   1.533 +    while (offset < restoreOffset) {
   1.534 +        op = peek_op_and_size(writer, offset, &opSize);
   1.535 +        if (is_drawing_op(op) || (SAVE_LAYER == op)) {
   1.536 +            // drawing verb, abort
   1.537 +            return false;
   1.538 +        }
   1.539 +        offset += opSize;
   1.540 +    }
   1.541 +
   1.542 +#ifdef TRACK_COLLAPSE_STATS
   1.543 +    gCollapseCount += 1;
   1.544 +    SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
   1.545 +             (double)gCollapseCount / gCollapseCalls, "%");
   1.546 +#endif
   1.547 +
   1.548 +    writer->rewindToOffset(saveOffset);
   1.549 +    return true;
   1.550 +}
   1.551 +
   1.552 +typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset,
   1.553 +                                     SkPaintDictionary* paintDict);
   1.554 +enum PictureRecordOptType {
   1.555 +    kRewind_OptType,  // Optimization rewinds the command stream
   1.556 +    kCollapseSaveLayer_OptType,  // Optimization eliminates a save/restore pair
   1.557 +};
   1.558 +
   1.559 +enum PictureRecordOptFlags {
   1.560 +    kSkipIfBBoxHierarchy_Flag = 0x1,  // Optimization should be skipped if the
   1.561 +                                      // SkPicture has a bounding box hierarchy.
   1.562 +};
   1.563 +
   1.564 +struct PictureRecordOpt {
   1.565 +    PictureRecordOptProc fProc;
   1.566 +    PictureRecordOptType fType;
   1.567 +    unsigned fFlags;
   1.568 +};
   1.569 +/*
   1.570 + * A list of the optimizations that are tried upon seeing a restore
   1.571 + * TODO: add a real API for such optimizations
   1.572 + *       Add the ability to fire optimizations on any op (not just RESTORE)
   1.573 + */
   1.574 +static const PictureRecordOpt gPictureRecordOpts[] = {
   1.575 +    // 'collapse_save_clip_restore' is skipped if there is a BBoxHierarchy
   1.576 +    // because it is redundant with the state traversal optimization in
   1.577 +    // SkPictureStateTree, and applying the optimization introduces significant
   1.578 +    // record time overhead because it requires rewinding contents that were
   1.579 +    // recorded into the BBoxHierarchy.
   1.580 +    { collapse_save_clip_restore, kRewind_OptType, kSkipIfBBoxHierarchy_Flag },
   1.581 +    { remove_save_layer1,         kCollapseSaveLayer_OptType, 0 },
   1.582 +    { remove_save_layer2,         kCollapseSaveLayer_OptType, 0 }
   1.583 +};
   1.584 +
   1.585 +// This is called after an optimization has been applied to the command stream
   1.586 +// in order to adjust the contents and state of the bounding box hierarchy and
   1.587 +// state tree to reflect the optimization.
   1.588 +static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree,
   1.589 +                                      SkBBoxHierarchy* boundingHierarchy) {
   1.590 +    switch (opt) {
   1.591 +    case kCollapseSaveLayer_OptType:
   1.592 +        if (NULL != stateTree) {
   1.593 +            stateTree->saveCollapsed();
   1.594 +        }
   1.595 +        break;
   1.596 +    case kRewind_OptType:
   1.597 +        if (NULL != boundingHierarchy) {
   1.598 +            boundingHierarchy->rewindInserts();
   1.599 +        }
   1.600 +        // Note: No need to touch the state tree for this to work correctly.
   1.601 +        // Unused branches do not burden the playback, and pruning the tree
   1.602 +        // would be O(N^2), so it is best to leave it alone.
   1.603 +        break;
   1.604 +    default:
   1.605 +        SkASSERT(0);
   1.606 +    }
   1.607 +}
   1.608 +
   1.609 +void SkPictureRecord::willRestore() {
   1.610 +    // FIXME: SkDeferredCanvas needs to be refactored to respect
   1.611 +    // save/restore balancing so that the following test can be
   1.612 +    // turned on permanently.
   1.613 +#if 0
   1.614 +    SkASSERT(fRestoreOffsetStack.count() > 1);
   1.615 +#endif
   1.616 +
   1.617 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.618 +    if (fMCMgr.getSaveCount() == 1) {
   1.619 +        return;
   1.620 +    }
   1.621 +
   1.622 +    fMCMgr.restore();
   1.623 +#else
   1.624 +    // check for underflow
   1.625 +    if (fRestoreOffsetStack.count() == 0) {
   1.626 +        return;
   1.627 +    }
   1.628 +
   1.629 +    if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
   1.630 +        fFirstSavedLayerIndex = kNoSavedLayerIndex;
   1.631 +    }
   1.632 +
   1.633 +    size_t opt = 0;
   1.634 +    if (fOptsEnabled) {
   1.635 +        for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) {
   1.636 +            if (0 != (gPictureRecordOpts[opt].fFlags & kSkipIfBBoxHierarchy_Flag)
   1.637 +                && NULL != fBoundingHierarchy) {
   1.638 +                continue;
   1.639 +            }
   1.640 +            if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) {
   1.641 +                // Some optimization fired so don't add the RESTORE
   1.642 +                apply_optimization_to_bbh(gPictureRecordOpts[opt].fType,
   1.643 +                                          fStateTree, fBoundingHierarchy);
   1.644 +                break;
   1.645 +            }
   1.646 +        }
   1.647 +    }
   1.648 +
   1.649 +    if (!fOptsEnabled || SK_ARRAY_COUNT(gPictureRecordOpts) == opt) {
   1.650 +        // No optimization fired so add the RESTORE
   1.651 +        this->recordRestore();
   1.652 +    }
   1.653 +
   1.654 +    fRestoreOffsetStack.pop();
   1.655 +#endif
   1.656 +
   1.657 +    this->INHERITED::willRestore();
   1.658 +}
   1.659 +
   1.660 +void SkPictureRecord::recordRestore(bool fillInSkips) {
   1.661 +    uint32_t initialOffset, size;
   1.662 +    if (fillInSkips) {
   1.663 +        this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
   1.664 +    }
   1.665 +    size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
   1.666 +    initialOffset = this->addDraw(RESTORE, &size);
   1.667 +    this->validate(initialOffset, size);
   1.668 +}
   1.669 +
   1.670 +void SkPictureRecord::didTranslate(SkScalar dx, SkScalar dy) {
   1.671 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.672 +    fMCMgr.translate(dx, dy);
   1.673 +#else
   1.674 +    // op + dx + dy
   1.675 +    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
   1.676 +    size_t initialOffset = this->addDraw(TRANSLATE, &size);
   1.677 +    this->addScalar(dx);
   1.678 +    this->addScalar(dy);
   1.679 +    this->validate(initialOffset, size);
   1.680 +#endif
   1.681 +    this->INHERITED::didTranslate(dx, dy);
   1.682 +}
   1.683 +
   1.684 +void SkPictureRecord::didScale(SkScalar sx, SkScalar sy) {
   1.685 +
   1.686 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.687 +    fMCMgr.scale(sx, sy);
   1.688 +#else
   1.689 +    // op + sx + sy
   1.690 +    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
   1.691 +    size_t initialOffset = this->addDraw(SCALE, &size);
   1.692 +    this->addScalar(sx);
   1.693 +    this->addScalar(sy);
   1.694 +    this->validate(initialOffset, size);
   1.695 +#endif
   1.696 +    this->INHERITED::didScale(sx, sy);
   1.697 +}
   1.698 +
   1.699 +void SkPictureRecord::didRotate(SkScalar degrees) {
   1.700 +
   1.701 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.702 +    fMCMgr.rotate(degrees);
   1.703 +#else
   1.704 +    // op + degrees
   1.705 +    uint32_t size = 1 * kUInt32Size + sizeof(SkScalar);
   1.706 +    size_t initialOffset = this->addDraw(ROTATE, &size);
   1.707 +    this->addScalar(degrees);
   1.708 +    this->validate(initialOffset, size);
   1.709 +#endif
   1.710 +    this->INHERITED::didRotate(degrees);
   1.711 +}
   1.712 +
   1.713 +void SkPictureRecord::didSkew(SkScalar sx, SkScalar sy) {
   1.714 +
   1.715 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.716 +    fMCMgr.skew(sx, sy);
   1.717 +#else
   1.718 +    // op + sx + sy
   1.719 +    uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
   1.720 +    size_t initialOffset = this->addDraw(SKEW, &size);
   1.721 +    this->addScalar(sx);
   1.722 +    this->addScalar(sy);
   1.723 +    this->validate(initialOffset, size);
   1.724 +#endif
   1.725 +    this->INHERITED::didSkew(sx, sy);
   1.726 +}
   1.727 +
   1.728 +void SkPictureRecord::didConcat(const SkMatrix& matrix) {
   1.729 +
   1.730 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.731 +    fMCMgr.concat(matrix);
   1.732 +#else
   1.733 +    this->recordConcat(matrix);
   1.734 +#endif
   1.735 +    this->INHERITED::didConcat(matrix);
   1.736 +}
   1.737 +
   1.738 +void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
   1.739 +    this->validate(fWriter.bytesWritten(), 0);
   1.740 +    // op + matrix
   1.741 +    uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
   1.742 +    size_t initialOffset = this->addDraw(CONCAT, &size);
   1.743 +    this->addMatrix(matrix);
   1.744 +    this->validate(initialOffset, size);
   1.745 +}
   1.746 +
   1.747 +void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
   1.748 +
   1.749 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.750 +    fMCMgr.setMatrix(matrix);
   1.751 +#else
   1.752 +    this->validate(fWriter.bytesWritten(), 0);
   1.753 +    // op + matrix
   1.754 +    uint32_t size = kUInt32Size + matrix.writeToMemory(NULL);
   1.755 +    size_t initialOffset = this->addDraw(SET_MATRIX, &size);
   1.756 +    this->addMatrix(matrix);
   1.757 +    this->validate(initialOffset, size);
   1.758 +#endif
   1.759 +    this->INHERITED::didSetMatrix(matrix);
   1.760 +}
   1.761 +
   1.762 +static bool regionOpExpands(SkRegion::Op op) {
   1.763 +    switch (op) {
   1.764 +        case SkRegion::kUnion_Op:
   1.765 +        case SkRegion::kXOR_Op:
   1.766 +        case SkRegion::kReverseDifference_Op:
   1.767 +        case SkRegion::kReplace_Op:
   1.768 +            return true;
   1.769 +        case SkRegion::kIntersect_Op:
   1.770 +        case SkRegion::kDifference_Op:
   1.771 +            return false;
   1.772 +        default:
   1.773 +            SkDEBUGFAIL("unknown region op");
   1.774 +            return false;
   1.775 +    }
   1.776 +}
   1.777 +
   1.778 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.779 +void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
   1.780 +    fMCMgr.fillInSkips(&fWriter, restoreOffset);
   1.781 +}
   1.782 +#else
   1.783 +void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
   1.784 +    int32_t offset = fRestoreOffsetStack.top();
   1.785 +    while (offset > 0) {
   1.786 +        uint32_t peek = fWriter.readTAt<uint32_t>(offset);
   1.787 +        fWriter.overwriteTAt(offset, restoreOffset);
   1.788 +        offset = peek;
   1.789 +    }
   1.790 +
   1.791 +#ifdef SK_DEBUG
   1.792 +    // assert that the final offset value points to a save verb
   1.793 +    uint32_t opSize;
   1.794 +    DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
   1.795 +    SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
   1.796 +#endif
   1.797 +}
   1.798 +#endif
   1.799 +
   1.800 +void SkPictureRecord::beginRecording() {
   1.801 +    // we have to call this *after* our constructor, to ensure that it gets
   1.802 +    // recorded. This is balanced by restoreToCount() call from endRecording,
   1.803 +    // which in-turn calls our overridden restore(), so those get recorded too.
   1.804 +    fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
   1.805 +}
   1.806 +
   1.807 +void SkPictureRecord::endRecording() {
   1.808 +    SkASSERT(kNoInitialSave != fInitialSaveCount);
   1.809 +    this->restoreToCount(fInitialSaveCount);
   1.810 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.811 +    fMCMgr.finish();
   1.812 +#endif
   1.813 +}
   1.814 +
   1.815 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.816 +int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
   1.817 +    size_t offset = fWriter.bytesWritten();
   1.818 +    this->addInt(-1);
   1.819 +    return offset;
   1.820 +}
   1.821 +#else
   1.822 +int SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
   1.823 +    if (fRestoreOffsetStack.isEmpty()) {
   1.824 +        return -1;
   1.825 +    }
   1.826 +
   1.827 +    // The RestoreOffset field is initially filled with a placeholder
   1.828 +    // value that points to the offset of the previous RestoreOffset
   1.829 +    // in the current stack level, thus forming a linked list so that
   1.830 +    // the restore offsets can be filled in when the corresponding
   1.831 +    // restore command is recorded.
   1.832 +    int32_t prevOffset = fRestoreOffsetStack.top();
   1.833 +
   1.834 +    if (regionOpExpands(op)) {
   1.835 +        // Run back through any previous clip ops, and mark their offset to
   1.836 +        // be 0, disabling their ability to trigger a jump-to-restore, otherwise
   1.837 +        // they could hide this clips ability to expand the clip (i.e. go from
   1.838 +        // empty to non-empty).
   1.839 +        this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
   1.840 +
   1.841 +        // Reset the pointer back to the previous clip so that subsequent
   1.842 +        // restores don't overwrite the offsets we just cleared.
   1.843 +        prevOffset = 0;
   1.844 +    }
   1.845 +
   1.846 +    size_t offset = fWriter.bytesWritten();
   1.847 +    this->addInt(prevOffset);
   1.848 +    fRestoreOffsetStack.top() = offset;
   1.849 +    return offset;
   1.850 +}
   1.851 +#endif
   1.852 +
   1.853 +void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
   1.854 +
   1.855 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.856 +    fMCMgr.clipRect(rect, op, doAA);
   1.857 +#else
   1.858 +    this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
   1.859 +#endif
   1.860 +    this->INHERITED::onClipRect(rect, op, edgeStyle);
   1.861 +}
   1.862 +
   1.863 +int SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
   1.864 +    // id + rect + clip params
   1.865 +    uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
   1.866 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.867 +    size += kUInt32Size;    // + restore offset
   1.868 +#else
   1.869 +    // recordRestoreOffsetPlaceholder doesn't always write an offset
   1.870 +    if (!fRestoreOffsetStack.isEmpty()) {
   1.871 +        // + restore offset
   1.872 +        size += kUInt32Size;
   1.873 +    }
   1.874 +#endif
   1.875 +    size_t initialOffset = this->addDraw(CLIP_RECT, &size);
   1.876 +    this->addRect(rect);
   1.877 +    this->addInt(ClipParams_pack(op, doAA));
   1.878 +    int offset = this->recordRestoreOffsetPlaceholder(op);
   1.879 +
   1.880 +    this->validate(initialOffset, size);
   1.881 +    return offset;
   1.882 +}
   1.883 +
   1.884 +void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
   1.885 +
   1.886 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.887 +    fMCMgr.clipRRect(rrect, op, doAA);
   1.888 +#else
   1.889 +    this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
   1.890 +#endif
   1.891 +    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
   1.892 +        this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
   1.893 +    } else {
   1.894 +        this->INHERITED::onClipRRect(rrect, op, edgeStyle);
   1.895 +    }
   1.896 +}
   1.897 +
   1.898 +int SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
   1.899 +    // op + rrect + clip params
   1.900 +    uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
   1.901 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.902 +    size += kUInt32Size;    // + restore offset
   1.903 +#else
   1.904 +    // recordRestoreOffsetPlaceholder doesn't always write an offset
   1.905 +    if (!fRestoreOffsetStack.isEmpty()) {
   1.906 +        // + restore offset
   1.907 +        size += kUInt32Size;
   1.908 +    }
   1.909 +#endif
   1.910 +    size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
   1.911 +    this->addRRect(rrect);
   1.912 +    this->addInt(ClipParams_pack(op, doAA));
   1.913 +    int offset = recordRestoreOffsetPlaceholder(op);
   1.914 +    this->validate(initialOffset, size);
   1.915 +    return offset;
   1.916 +}
   1.917 +
   1.918 +void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
   1.919 +
   1.920 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.921 +    fMCMgr.clipPath(path, op, doAA);
   1.922 +#else
   1.923 +    int pathID = this->addPathToHeap(path);
   1.924 +    this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
   1.925 +#endif
   1.926 +
   1.927 +    if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
   1.928 +        this->updateClipConservativelyUsingBounds(path.getBounds(), op,
   1.929 +                                                  path.isInverseFillType());
   1.930 +    } else {
   1.931 +        this->INHERITED::onClipPath(path, op, edgeStyle);
   1.932 +    }
   1.933 +}
   1.934 +
   1.935 +int SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
   1.936 +    // op + path index + clip params
   1.937 +    uint32_t size = 3 * kUInt32Size;
   1.938 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.939 +    size += kUInt32Size;    // + restore offset
   1.940 +#else
   1.941 +    // recordRestoreOffsetPlaceholder doesn't always write an offset
   1.942 +    if (!fRestoreOffsetStack.isEmpty()) {
   1.943 +        // + restore offset
   1.944 +        size += kUInt32Size;
   1.945 +    }
   1.946 +#endif
   1.947 +    size_t initialOffset = this->addDraw(CLIP_PATH, &size);
   1.948 +    this->addInt(pathID);
   1.949 +    this->addInt(ClipParams_pack(op, doAA));
   1.950 +    int offset = recordRestoreOffsetPlaceholder(op);
   1.951 +    this->validate(initialOffset, size);
   1.952 +    return offset;
   1.953 +}
   1.954 +
   1.955 +void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
   1.956 +
   1.957 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.958 +    fMCMgr.clipRegion(region, op);
   1.959 +#else
   1.960 +    this->recordClipRegion(region, op);
   1.961 +#endif
   1.962 +    this->INHERITED::onClipRegion(region, op);
   1.963 +}
   1.964 +
   1.965 +int SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
   1.966 +    // op + clip params + region
   1.967 +    uint32_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
   1.968 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.969 +    size += kUInt32Size;    // + restore offset
   1.970 +#else
   1.971 +    // recordRestoreOffsetPlaceholder doesn't always write an offset
   1.972 +    if (!fRestoreOffsetStack.isEmpty()) {
   1.973 +        // + restore offset
   1.974 +        size += kUInt32Size;
   1.975 +    }
   1.976 +#endif
   1.977 +    size_t initialOffset = this->addDraw(CLIP_REGION, &size);
   1.978 +    this->addRegion(region);
   1.979 +    this->addInt(ClipParams_pack(op, false));
   1.980 +    int offset = this->recordRestoreOffsetPlaceholder(op);
   1.981 +
   1.982 +    this->validate(initialOffset, size);
   1.983 +    return offset;
   1.984 +}
   1.985 +
   1.986 +void SkPictureRecord::clear(SkColor color) {
   1.987 +
   1.988 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
   1.989 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
   1.990 +#endif
   1.991 +
   1.992 +    // op + color
   1.993 +    uint32_t size = 2 * kUInt32Size;
   1.994 +    size_t initialOffset = this->addDraw(DRAW_CLEAR, &size);
   1.995 +    this->addInt(color);
   1.996 +    this->validate(initialOffset, size);
   1.997 +}
   1.998 +
   1.999 +void SkPictureRecord::drawPaint(const SkPaint& paint) {
  1.1000 +
  1.1001 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1002 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1003 +#endif
  1.1004 +
  1.1005 +    // op + paint index
  1.1006 +    uint32_t size = 2 * kUInt32Size;
  1.1007 +    size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
  1.1008 +    SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.bytesWritten());
  1.1009 +    this->addPaint(paint);
  1.1010 +    this->validate(initialOffset, size);
  1.1011 +}
  1.1012 +
  1.1013 +void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
  1.1014 +                                 const SkPaint& paint) {
  1.1015 +
  1.1016 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1017 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1018 +#endif
  1.1019 +
  1.1020 +    // op + paint index + mode + count + point data
  1.1021 +    uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
  1.1022 +    size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
  1.1023 +    SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.bytesWritten());
  1.1024 +    this->addPaint(paint);
  1.1025 +    this->addInt(mode);
  1.1026 +    this->addInt(count);
  1.1027 +    fWriter.writeMul4(pts, count * sizeof(SkPoint));
  1.1028 +    this->validate(initialOffset, size);
  1.1029 +}
  1.1030 +
  1.1031 +void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
  1.1032 +
  1.1033 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1034 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1035 +#endif
  1.1036 +
  1.1037 +    // op + paint index + rect
  1.1038 +    uint32_t size = 2 * kUInt32Size + sizeof(oval);
  1.1039 +    size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
  1.1040 +    SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.bytesWritten());
  1.1041 +    this->addPaint(paint);
  1.1042 +    this->addRect(oval);
  1.1043 +    this->validate(initialOffset, size);
  1.1044 +}
  1.1045 +
  1.1046 +void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
  1.1047 +
  1.1048 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1049 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1050 +#endif
  1.1051 +
  1.1052 +    // op + paint index + rect
  1.1053 +    uint32_t size = 2 * kUInt32Size + sizeof(rect);
  1.1054 +    size_t initialOffset = this->addDraw(DRAW_RECT, &size);
  1.1055 +    SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.bytesWritten());
  1.1056 +    this->addPaint(paint);
  1.1057 +    this->addRect(rect);
  1.1058 +    this->validate(initialOffset, size);
  1.1059 +}
  1.1060 +
  1.1061 +void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
  1.1062 +
  1.1063 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1064 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1065 +#endif
  1.1066 +
  1.1067 +    if (rrect.isRect()) {
  1.1068 +        this->SkPictureRecord::drawRect(rrect.getBounds(), paint);
  1.1069 +    } else if (rrect.isOval()) {
  1.1070 +        this->SkPictureRecord::drawOval(rrect.getBounds(), paint);
  1.1071 +    } else {
  1.1072 +        // op + paint index + rrect
  1.1073 +        uint32_t initialOffset, size;
  1.1074 +        size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
  1.1075 +        initialOffset = this->addDraw(DRAW_RRECT, &size);
  1.1076 +        SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.bytesWritten());
  1.1077 +        this->addPaint(paint);
  1.1078 +        this->addRRect(rrect);
  1.1079 +        this->validate(initialOffset, size);
  1.1080 +    }
  1.1081 +}
  1.1082 +
  1.1083 +void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
  1.1084 +                                   const SkPaint& paint) {
  1.1085 +
  1.1086 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1087 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1088 +#endif
  1.1089 +
  1.1090 +    // op + paint index + rrects
  1.1091 +    uint32_t initialOffset, size;
  1.1092 +    size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
  1.1093 +    initialOffset = this->addDraw(DRAW_DRRECT, &size);
  1.1094 +    SkASSERT(initialOffset+getPaintOffset(DRAW_DRRECT, size) == fWriter.bytesWritten());
  1.1095 +    this->addPaint(paint);
  1.1096 +    this->addRRect(outer);
  1.1097 +    this->addRRect(inner);
  1.1098 +    this->validate(initialOffset, size);
  1.1099 +}
  1.1100 +
  1.1101 +void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
  1.1102 +
  1.1103 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1104 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1105 +#endif
  1.1106 +
  1.1107 +    // op + paint index + path index
  1.1108 +    uint32_t size = 3 * kUInt32Size;
  1.1109 +    size_t initialOffset = this->addDraw(DRAW_PATH, &size);
  1.1110 +    SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.bytesWritten());
  1.1111 +    this->addPaint(paint);
  1.1112 +    this->addPath(path);
  1.1113 +    this->validate(initialOffset, size);
  1.1114 +}
  1.1115 +
  1.1116 +void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
  1.1117 +                                 const SkPaint* paint = NULL) {
  1.1118 +    if (bitmap.drawsNothing()) {
  1.1119 +        return;
  1.1120 +    }
  1.1121 +
  1.1122 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1123 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1124 +#endif
  1.1125 +
  1.1126 +    // op + paint index + bitmap index + left + top
  1.1127 +    uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
  1.1128 +    size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
  1.1129 +    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.bytesWritten());
  1.1130 +    this->addPaintPtr(paint);
  1.1131 +    int bitmapID = this->addBitmap(bitmap);
  1.1132 +    this->addScalar(left);
  1.1133 +    this->addScalar(top);
  1.1134 +    this->validate(initialOffset, size);
  1.1135 +    this->trackBitmapUse(bitmapID, initialOffset);
  1.1136 +}
  1.1137 +
  1.1138 +void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
  1.1139 +                                           const SkRect& dst, const SkPaint* paint,
  1.1140 +                                           DrawBitmapRectFlags flags) {
  1.1141 +    if (bitmap.drawsNothing()) {
  1.1142 +        return;
  1.1143 +    }
  1.1144 +
  1.1145 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1146 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1147 +#endif
  1.1148 +    // id + paint index + bitmap index + bool for 'src' + flags
  1.1149 +    uint32_t size = 5 * kUInt32Size;
  1.1150 +    if (NULL != src) {
  1.1151 +        size += sizeof(*src);   // + rect
  1.1152 +    }
  1.1153 +    size += sizeof(dst);        // + rect
  1.1154 +
  1.1155 +    size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
  1.1156 +    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size)
  1.1157 +             == fWriter.bytesWritten());
  1.1158 +    this->addPaintPtr(paint);
  1.1159 +    int bitmapID = this->addBitmap(bitmap);
  1.1160 +    this->addRectPtr(src);  // may be null
  1.1161 +    this->addRect(dst);
  1.1162 +    this->addInt(flags);
  1.1163 +    this->validate(initialOffset, size);
  1.1164 +    this->trackBitmapUse(bitmapID, initialOffset);
  1.1165 +}
  1.1166 +
  1.1167 +void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
  1.1168 +                                       const SkPaint* paint) {
  1.1169 +    if (bitmap.drawsNothing()) {
  1.1170 +        return;
  1.1171 +    }
  1.1172 +
  1.1173 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1174 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1175 +#endif
  1.1176 +
  1.1177 +    // id + paint index + bitmap index + matrix
  1.1178 +    uint32_t size = 3 * kUInt32Size + matrix.writeToMemory(NULL);
  1.1179 +    size_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size);
  1.1180 +    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.bytesWritten());
  1.1181 +    this->addPaintPtr(paint);
  1.1182 +    int bitmapID = this->addBitmap(bitmap);
  1.1183 +    this->addMatrix(matrix);
  1.1184 +    this->validate(initialOffset, size);
  1.1185 +    this->trackBitmapUse(bitmapID, initialOffset);
  1.1186 +}
  1.1187 +
  1.1188 +void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
  1.1189 +                                     const SkRect& dst, const SkPaint* paint) {
  1.1190 +    if (bitmap.drawsNothing()) {
  1.1191 +        return;
  1.1192 +    }
  1.1193 +
  1.1194 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1195 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1196 +#endif
  1.1197 +
  1.1198 +    // op + paint index + bitmap id + center + dst rect
  1.1199 +    uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
  1.1200 +    size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
  1.1201 +    SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
  1.1202 +    this->addPaintPtr(paint);
  1.1203 +    int bitmapID = this->addBitmap(bitmap);
  1.1204 +    this->addIRect(center);
  1.1205 +    this->addRect(dst);
  1.1206 +    this->validate(initialOffset, size);
  1.1207 +    this->trackBitmapUse(bitmapID, initialOffset);
  1.1208 +}
  1.1209 +
  1.1210 +void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
  1.1211 +                                 const SkPaint* paint = NULL) {
  1.1212 +    if (bitmap.drawsNothing()) {
  1.1213 +        return;
  1.1214 +    }
  1.1215 +
  1.1216 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1217 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1218 +#endif
  1.1219 +
  1.1220 +    // op + paint index + bitmap index + left + top
  1.1221 +    uint32_t size = 5 * kUInt32Size;
  1.1222 +    size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
  1.1223 +    SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.bytesWritten());
  1.1224 +    this->addPaintPtr(paint);
  1.1225 +    int bitmapID = this->addBitmap(bitmap);
  1.1226 +    this->addInt(left);
  1.1227 +    this->addInt(top);
  1.1228 +    this->validate(initialOffset, size);
  1.1229 +    this->trackBitmapUse(bitmapID, initialOffset);
  1.1230 +}
  1.1231 +
  1.1232 +void SkPictureRecord::ComputeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
  1.1233 +    SkPaint::FontMetrics metrics;
  1.1234 +    paint.getFontMetrics(&metrics);
  1.1235 +    SkRect bounds;
  1.1236 +    // construct a rect so we can see any adjustments from the paint.
  1.1237 +    // we use 0,1 for left,right, just so the rect isn't empty
  1.1238 +    bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
  1.1239 +    (void)paint.computeFastBounds(bounds, &bounds);
  1.1240 +    topbot[0] = bounds.fTop;
  1.1241 +    topbot[1] = bounds.fBottom;
  1.1242 +}
  1.1243 +
  1.1244 +void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
  1.1245 +                                              SkScalar minY, SkScalar maxY) {
  1.1246 +    WriteTopBot(paint, flat);
  1.1247 +    this->addScalar(flat.topBot()[0] + minY);
  1.1248 +    this->addScalar(flat.topBot()[1] + maxY);
  1.1249 +}
  1.1250 +
  1.1251 +void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
  1.1252 +                      SkScalar y, const SkPaint& paint) {
  1.1253 +
  1.1254 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1255 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1256 +#endif
  1.1257 +
  1.1258 +    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
  1.1259 +
  1.1260 +    // op + paint index + length + 'length' worth of chars + x + y
  1.1261 +    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
  1.1262 +    if (fast) {
  1.1263 +        size += 2 * sizeof(SkScalar); // + top & bottom
  1.1264 +    }
  1.1265 +
  1.1266 +    DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT;
  1.1267 +    size_t initialOffset = this->addDraw(op, &size);
  1.1268 +    SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
  1.1269 +    const SkFlatData* flatPaintData = addPaint(paint);
  1.1270 +    SkASSERT(flatPaintData);
  1.1271 +    this->addText(text, byteLength);
  1.1272 +    this->addScalar(x);
  1.1273 +    this->addScalar(y);
  1.1274 +    if (fast) {
  1.1275 +        this->addFontMetricsTopBottom(paint, *flatPaintData, y, y);
  1.1276 +    }
  1.1277 +    this->validate(initialOffset, size);
  1.1278 +}
  1.1279 +
  1.1280 +void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
  1.1281 +                         const SkPoint pos[], const SkPaint& paint) {
  1.1282 +
  1.1283 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1284 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1285 +#endif
  1.1286 +
  1.1287 +    size_t points = paint.countText(text, byteLength);
  1.1288 +    if (0 == points)
  1.1289 +        return;
  1.1290 +
  1.1291 +    bool canUseDrawH = true;
  1.1292 +    SkScalar minY = pos[0].fY;
  1.1293 +    SkScalar maxY = pos[0].fY;
  1.1294 +    // check if the caller really should have used drawPosTextH()
  1.1295 +    {
  1.1296 +        const SkScalar firstY = pos[0].fY;
  1.1297 +        for (size_t index = 1; index < points; index++) {
  1.1298 +            if (pos[index].fY != firstY) {
  1.1299 +                canUseDrawH = false;
  1.1300 +                if (pos[index].fY < minY) {
  1.1301 +                    minY = pos[index].fY;
  1.1302 +                } else if (pos[index].fY > maxY) {
  1.1303 +                    maxY = pos[index].fY;
  1.1304 +                }
  1.1305 +            }
  1.1306 +        }
  1.1307 +    }
  1.1308 +
  1.1309 +    bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
  1.1310 +    bool fast = canUseDrawH && fastBounds;
  1.1311 +
  1.1312 +    // op + paint index + length + 'length' worth of data + num points
  1.1313 +    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
  1.1314 +    if (canUseDrawH) {
  1.1315 +        if (fast) {
  1.1316 +            size += 2 * sizeof(SkScalar); // + top & bottom
  1.1317 +        }
  1.1318 +        // + y-pos + actual x-point data
  1.1319 +        size += sizeof(SkScalar) + points * sizeof(SkScalar);
  1.1320 +    } else {
  1.1321 +        // + x&y point data
  1.1322 +        size += points * sizeof(SkPoint);
  1.1323 +        if (fastBounds) {
  1.1324 +            size += 2 * sizeof(SkScalar); // + top & bottom
  1.1325 +        }
  1.1326 +    }
  1.1327 +
  1.1328 +    DrawType op;
  1.1329 +    if (fast) {
  1.1330 +        op = DRAW_POS_TEXT_H_TOP_BOTTOM;
  1.1331 +    } else if (canUseDrawH) {
  1.1332 +        op = DRAW_POS_TEXT_H;
  1.1333 +    } else if (fastBounds) {
  1.1334 +        op = DRAW_POS_TEXT_TOP_BOTTOM;
  1.1335 +    } else {
  1.1336 +        op = DRAW_POS_TEXT;
  1.1337 +    }
  1.1338 +    size_t initialOffset = this->addDraw(op, &size);
  1.1339 +    SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.bytesWritten());
  1.1340 +    const SkFlatData* flatPaintData = this->addPaint(paint);
  1.1341 +    SkASSERT(flatPaintData);
  1.1342 +    this->addText(text, byteLength);
  1.1343 +    this->addInt(points);
  1.1344 +
  1.1345 +#ifdef SK_DEBUG_SIZE
  1.1346 +    size_t start = fWriter.bytesWritten();
  1.1347 +#endif
  1.1348 +    if (canUseDrawH) {
  1.1349 +        if (fast) {
  1.1350 +            this->addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
  1.1351 +        }
  1.1352 +        this->addScalar(pos[0].fY);
  1.1353 +        SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
  1.1354 +        for (size_t index = 0; index < points; index++)
  1.1355 +            *xptr++ = pos[index].fX;
  1.1356 +    } else {
  1.1357 +        fWriter.writeMul4(pos, points * sizeof(SkPoint));
  1.1358 +        if (fastBounds) {
  1.1359 +            this->addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
  1.1360 +        }
  1.1361 +    }
  1.1362 +#ifdef SK_DEBUG_SIZE
  1.1363 +    fPointBytes += fWriter.bytesWritten() - start;
  1.1364 +    fPointWrites += points;
  1.1365 +#endif
  1.1366 +    this->validate(initialOffset, size);
  1.1367 +}
  1.1368 +
  1.1369 +void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
  1.1370 +                          const SkScalar xpos[], SkScalar constY,
  1.1371 +                          const SkPaint& paint) {
  1.1372 +
  1.1373 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1374 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1375 +#endif
  1.1376 +
  1.1377 +    const SkFlatData* flatPaintData = this->getFlatPaintData(paint);
  1.1378 +    this->drawPosTextHImpl(text, byteLength, xpos, constY, paint, flatPaintData);
  1.1379 +}
  1.1380 +
  1.1381 +void SkPictureRecord::drawPosTextHImpl(const void* text, size_t byteLength,
  1.1382 +                          const SkScalar xpos[], SkScalar constY,
  1.1383 +                          const SkPaint& paint, const SkFlatData* flatPaintData) {
  1.1384 +    size_t points = paint.countText(text, byteLength);
  1.1385 +    if (0 == points)
  1.1386 +        return;
  1.1387 +
  1.1388 +    bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
  1.1389 +
  1.1390 +    // op + paint index + length + 'length' worth of data + num points
  1.1391 +    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
  1.1392 +    if (fast) {
  1.1393 +        size += 2 * sizeof(SkScalar); // + top & bottom
  1.1394 +    }
  1.1395 +    // + y + the actual points
  1.1396 +    size += 1 * kUInt32Size + points * sizeof(SkScalar);
  1.1397 +    size_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H,
  1.1398 +                                         &size);
  1.1399 +    SkASSERT(flatPaintData);
  1.1400 +    this->addFlatPaint(flatPaintData);
  1.1401 +
  1.1402 +    this->addText(text, byteLength);
  1.1403 +    this->addInt(points);
  1.1404 +
  1.1405 +#ifdef SK_DEBUG_SIZE
  1.1406 +    size_t start = fWriter.bytesWritten();
  1.1407 +#endif
  1.1408 +    if (fast) {
  1.1409 +        this->addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
  1.1410 +    }
  1.1411 +    this->addScalar(constY);
  1.1412 +    fWriter.writeMul4(xpos, points * sizeof(SkScalar));
  1.1413 +#ifdef SK_DEBUG_SIZE
  1.1414 +    fPointBytes += fWriter.bytesWritten() - start;
  1.1415 +    fPointWrites += points;
  1.1416 +#endif
  1.1417 +    this->validate(initialOffset, size);
  1.1418 +}
  1.1419 +
  1.1420 +void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
  1.1421 +                            const SkPath& path, const SkMatrix* matrix,
  1.1422 +                            const SkPaint& paint) {
  1.1423 +
  1.1424 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1425 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1426 +#endif
  1.1427 +
  1.1428 +    // op + paint index + length + 'length' worth of data + path index + matrix
  1.1429 +    const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
  1.1430 +    uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
  1.1431 +    size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
  1.1432 +    SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
  1.1433 +    this->addPaint(paint);
  1.1434 +    this->addText(text, byteLength);
  1.1435 +    this->addPath(path);
  1.1436 +    this->addMatrix(m);
  1.1437 +    this->validate(initialOffset, size);
  1.1438 +}
  1.1439 +
  1.1440 +void SkPictureRecord::drawPicture(SkPicture& picture) {
  1.1441 +
  1.1442 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1443 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1444 +#endif
  1.1445 +
  1.1446 +    // op + picture index
  1.1447 +    uint32_t size = 2 * kUInt32Size;
  1.1448 +    size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
  1.1449 +    this->addPicture(picture);
  1.1450 +    this->validate(initialOffset, size);
  1.1451 +}
  1.1452 +
  1.1453 +void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
  1.1454 +                          const SkPoint vertices[], const SkPoint texs[],
  1.1455 +                          const SkColor colors[], SkXfermode* xfer,
  1.1456 +                          const uint16_t indices[], int indexCount,
  1.1457 +                          const SkPaint& paint) {
  1.1458 +
  1.1459 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1460 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1461 +#endif
  1.1462 +
  1.1463 +    uint32_t flags = 0;
  1.1464 +    if (texs) {
  1.1465 +        flags |= DRAW_VERTICES_HAS_TEXS;
  1.1466 +    }
  1.1467 +    if (colors) {
  1.1468 +        flags |= DRAW_VERTICES_HAS_COLORS;
  1.1469 +    }
  1.1470 +    if (indexCount > 0) {
  1.1471 +        flags |= DRAW_VERTICES_HAS_INDICES;
  1.1472 +    }
  1.1473 +    if (NULL != xfer) {
  1.1474 +        SkXfermode::Mode mode;
  1.1475 +        if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
  1.1476 +            flags |= DRAW_VERTICES_HAS_XFER;
  1.1477 +        }
  1.1478 +    }
  1.1479 +
  1.1480 +    // op + paint index + flags + vmode + vCount + vertices
  1.1481 +    uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
  1.1482 +    if (flags & DRAW_VERTICES_HAS_TEXS) {
  1.1483 +        size += vertexCount * sizeof(SkPoint);  // + uvs
  1.1484 +    }
  1.1485 +    if (flags & DRAW_VERTICES_HAS_COLORS) {
  1.1486 +        size += vertexCount * sizeof(SkColor);  // + vert colors
  1.1487 +    }
  1.1488 +    if (flags & DRAW_VERTICES_HAS_INDICES) {
  1.1489 +        // + num indices + indices
  1.1490 +        size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
  1.1491 +    }
  1.1492 +    if (flags & DRAW_VERTICES_HAS_XFER) {
  1.1493 +        size += kUInt32Size;    // mode enum
  1.1494 +    }
  1.1495 +
  1.1496 +    size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
  1.1497 +    SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.bytesWritten());
  1.1498 +    this->addPaint(paint);
  1.1499 +    this->addInt(flags);
  1.1500 +    this->addInt(vmode);
  1.1501 +    this->addInt(vertexCount);
  1.1502 +    this->addPoints(vertices, vertexCount);
  1.1503 +    if (flags & DRAW_VERTICES_HAS_TEXS) {
  1.1504 +        this->addPoints(texs, vertexCount);
  1.1505 +    }
  1.1506 +    if (flags & DRAW_VERTICES_HAS_COLORS) {
  1.1507 +        fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
  1.1508 +    }
  1.1509 +    if (flags & DRAW_VERTICES_HAS_INDICES) {
  1.1510 +        this->addInt(indexCount);
  1.1511 +        fWriter.writePad(indices, indexCount * sizeof(uint16_t));
  1.1512 +    }
  1.1513 +    if (flags & DRAW_VERTICES_HAS_XFER) {
  1.1514 +        SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
  1.1515 +        (void)xfer->asMode(&mode);
  1.1516 +        this->addInt(mode);
  1.1517 +    }
  1.1518 +    this->validate(initialOffset, size);
  1.1519 +}
  1.1520 +
  1.1521 +void SkPictureRecord::drawData(const void* data, size_t length) {
  1.1522 +
  1.1523 +#ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
  1.1524 +    fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
  1.1525 +#endif
  1.1526 +
  1.1527 +    // op + length + 'length' worth of data
  1.1528 +    uint32_t size = 2 * kUInt32Size + SkAlign4(length);
  1.1529 +    size_t initialOffset = this->addDraw(DRAW_DATA, &size);
  1.1530 +    this->addInt(length);
  1.1531 +    fWriter.writePad(data, length);
  1.1532 +    this->validate(initialOffset, size);
  1.1533 +}
  1.1534 +
  1.1535 +void SkPictureRecord::beginCommentGroup(const char* description) {
  1.1536 +    // op/size + length of string + \0 terminated chars
  1.1537 +    int length = strlen(description);
  1.1538 +    uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1);
  1.1539 +    size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
  1.1540 +    fWriter.writeString(description, length);
  1.1541 +    this->validate(initialOffset, size);
  1.1542 +}
  1.1543 +
  1.1544 +void SkPictureRecord::addComment(const char* kywd, const char* value) {
  1.1545 +    // op/size + 2x length of string + 2x \0 terminated chars
  1.1546 +    int kywdLen = strlen(kywd);
  1.1547 +    int valueLen = strlen(value);
  1.1548 +    uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
  1.1549 +    size_t initialOffset = this->addDraw(COMMENT, &size);
  1.1550 +    fWriter.writeString(kywd, kywdLen);
  1.1551 +    fWriter.writeString(value, valueLen);
  1.1552 +    this->validate(initialOffset, size);
  1.1553 +}
  1.1554 +
  1.1555 +void SkPictureRecord::endCommentGroup() {
  1.1556 +    // op/size
  1.1557 +    uint32_t size = 1 * kUInt32Size;
  1.1558 +    size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
  1.1559 +    this->validate(initialOffset, size);
  1.1560 +}
  1.1561 +
  1.1562 +// [op/size] [rect] [skip offset]
  1.1563 +static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect);
  1.1564 +void SkPictureRecord::onPushCull(const SkRect& cullRect) {
  1.1565 +    // Skip identical cull rects.
  1.1566 +    if (!fCullOffsetStack.isEmpty()) {
  1.1567 +        const SkRect& prevCull = fWriter.readTAt<SkRect>(fCullOffsetStack.top() - sizeof(SkRect));
  1.1568 +        if (prevCull == cullRect) {
  1.1569 +            // Skipped culls are tracked on the stack, but they point to the previous offset.
  1.1570 +            fCullOffsetStack.push(fCullOffsetStack.top());
  1.1571 +            return;
  1.1572 +        }
  1.1573 +
  1.1574 +        SkASSERT(prevCull.contains(cullRect));
  1.1575 +    }
  1.1576 +
  1.1577 +    uint32_t size = kPushCullOpSize;
  1.1578 +    size_t initialOffset = this->addDraw(PUSH_CULL, &size);
  1.1579 +    // PUSH_CULL's size should stay constant (used to rewind).
  1.1580 +    SkASSERT(size == kPushCullOpSize);
  1.1581 +
  1.1582 +    this->addRect(cullRect);
  1.1583 +    fCullOffsetStack.push(fWriter.bytesWritten());
  1.1584 +    this->addInt(0);
  1.1585 +    this->validate(initialOffset, size);
  1.1586 +}
  1.1587 +
  1.1588 +void SkPictureRecord::onPopCull() {
  1.1589 +    SkASSERT(!fCullOffsetStack.isEmpty());
  1.1590 +
  1.1591 +    uint32_t cullSkipOffset = fCullOffsetStack.top();
  1.1592 +    fCullOffsetStack.pop();
  1.1593 +
  1.1594 +    // Skipped push, do the same for pop.
  1.1595 +    if (!fCullOffsetStack.isEmpty() && cullSkipOffset == fCullOffsetStack.top()) {
  1.1596 +        return;
  1.1597 +    }
  1.1598 +
  1.1599 +    // Collapse empty push/pop pairs.
  1.1600 +    if ((size_t)(cullSkipOffset + kUInt32Size) == fWriter.bytesWritten()) {
  1.1601 +        SkASSERT(fWriter.bytesWritten() >= kPushCullOpSize);
  1.1602 +        SkASSERT(PUSH_CULL == peek_op(&fWriter, fWriter.bytesWritten() - kPushCullOpSize));
  1.1603 +        fWriter.rewindToOffset(fWriter.bytesWritten() - kPushCullOpSize);
  1.1604 +        return;
  1.1605 +    }
  1.1606 +
  1.1607 +    // op only
  1.1608 +    uint32_t size = kUInt32Size;
  1.1609 +    size_t initialOffset = this->addDraw(POP_CULL, &size);
  1.1610 +
  1.1611 +    // update the cull skip offset to point past this op.
  1.1612 +    fWriter.overwriteTAt<uint32_t>(cullSkipOffset, fWriter.bytesWritten());
  1.1613 +
  1.1614 +    this->validate(initialOffset, size);
  1.1615 +}
  1.1616 +
  1.1617 +///////////////////////////////////////////////////////////////////////////////
  1.1618 +
  1.1619 +SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info) {
  1.1620 +    return SkSurface::NewPicture(info.fWidth, info.fHeight);
  1.1621 +}
  1.1622 +
  1.1623 +void SkPictureRecord::trackBitmapUse(int bitmapID, size_t offset) {
  1.1624 +#ifndef SK_ALLOW_BITMAP_TRACKING
  1.1625 +    return;
  1.1626 +#endif
  1.1627 +
  1.1628 +    if (!(fRecordFlags & SkPicture::kOptimizeForClippedPlayback_RecordingFlag)) {
  1.1629 +        return;
  1.1630 +    }
  1.1631 +
  1.1632 +    if (SkBitmapHeap::INVALID_SLOT == bitmapID) {
  1.1633 +        return;
  1.1634 +    }
  1.1635 +
  1.1636 +    if (NULL == fBitmapUseOffsets) {
  1.1637 +        fBitmapUseOffsets.reset(SkNEW(SkOffsetTable));
  1.1638 +    }
  1.1639 +
  1.1640 +    fBitmapUseOffsets->add(bitmapID, offset);
  1.1641 +}
  1.1642 +
  1.1643 +int SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
  1.1644 +    const int index = fBitmapHeap->insert(bitmap);
  1.1645 +    // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
  1.1646 +    // release builds, the invalid value will be recorded so that the reader will know that there
  1.1647 +    // was a problem.
  1.1648 +    SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
  1.1649 +    this->addInt(index);
  1.1650 +    return index;
  1.1651 +}
  1.1652 +
  1.1653 +void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
  1.1654 +    fWriter.writeMatrix(matrix);
  1.1655 +}
  1.1656 +
  1.1657 +const SkFlatData* SkPictureRecord::getFlatPaintData(const SkPaint& paint) {
  1.1658 +    return fPaints.findAndReturnFlat(paint);
  1.1659 +}
  1.1660 +
  1.1661 +const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
  1.1662 +    const SkFlatData* data = paint ? getFlatPaintData(*paint) : NULL;
  1.1663 +    this->addFlatPaint(data);
  1.1664 +    return data;
  1.1665 +}
  1.1666 +
  1.1667 +void SkPictureRecord::addFlatPaint(const SkFlatData* flatPaint) {
  1.1668 +    int index = flatPaint ? flatPaint->index() : 0;
  1.1669 +    this->addInt(index);
  1.1670 +}
  1.1671 +
  1.1672 +int SkPictureRecord::addPathToHeap(const SkPath& path) {
  1.1673 +    if (NULL == fPathHeap) {
  1.1674 +        fPathHeap = SkNEW(SkPathHeap);
  1.1675 +    }
  1.1676 +#ifdef SK_DEDUP_PICTURE_PATHS
  1.1677 +    return fPathHeap->insert(path);
  1.1678 +#else
  1.1679 +    return fPathHeap->append(path);
  1.1680 +#endif
  1.1681 +}
  1.1682 +
  1.1683 +void SkPictureRecord::addPath(const SkPath& path) {
  1.1684 +    this->addInt(this->addPathToHeap(path));
  1.1685 +}
  1.1686 +
  1.1687 +void SkPictureRecord::addPicture(SkPicture& picture) {
  1.1688 +    int index = fPictureRefs.find(&picture);
  1.1689 +    if (index < 0) {    // not found
  1.1690 +        index = fPictureRefs.count();
  1.1691 +        *fPictureRefs.append() = &picture;
  1.1692 +        picture.ref();
  1.1693 +    }
  1.1694 +    // follow the convention of recording a 1-based index
  1.1695 +    this->addInt(index + 1);
  1.1696 +}
  1.1697 +
  1.1698 +void SkPictureRecord::addPoint(const SkPoint& point) {
  1.1699 +#ifdef SK_DEBUG_SIZE
  1.1700 +    size_t start = fWriter.bytesWritten();
  1.1701 +#endif
  1.1702 +    fWriter.writePoint(point);
  1.1703 +#ifdef SK_DEBUG_SIZE
  1.1704 +    fPointBytes += fWriter.bytesWritten() - start;
  1.1705 +    fPointWrites++;
  1.1706 +#endif
  1.1707 +}
  1.1708 +
  1.1709 +void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
  1.1710 +    fWriter.writeMul4(pts, count * sizeof(SkPoint));
  1.1711 +#ifdef SK_DEBUG_SIZE
  1.1712 +    fPointBytes += count * sizeof(SkPoint);
  1.1713 +    fPointWrites++;
  1.1714 +#endif
  1.1715 +}
  1.1716 +
  1.1717 +void SkPictureRecord::addRect(const SkRect& rect) {
  1.1718 +#ifdef SK_DEBUG_SIZE
  1.1719 +    size_t start = fWriter.bytesWritten();
  1.1720 +#endif
  1.1721 +    fWriter.writeRect(rect);
  1.1722 +#ifdef SK_DEBUG_SIZE
  1.1723 +    fRectBytes += fWriter.bytesWritten() - start;
  1.1724 +    fRectWrites++;
  1.1725 +#endif
  1.1726 +}
  1.1727 +
  1.1728 +void SkPictureRecord::addRectPtr(const SkRect* rect) {
  1.1729 +    if (fWriter.writeBool(rect != NULL)) {
  1.1730 +        fWriter.writeRect(*rect);
  1.1731 +    }
  1.1732 +}
  1.1733 +
  1.1734 +void SkPictureRecord::addIRect(const SkIRect& rect) {
  1.1735 +    fWriter.write(&rect, sizeof(rect));
  1.1736 +}
  1.1737 +
  1.1738 +void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
  1.1739 +    if (fWriter.writeBool(rect != NULL)) {
  1.1740 +        *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
  1.1741 +    }
  1.1742 +}
  1.1743 +
  1.1744 +void SkPictureRecord::addRRect(const SkRRect& rrect) {
  1.1745 +    fWriter.writeRRect(rrect);
  1.1746 +}
  1.1747 +
  1.1748 +void SkPictureRecord::addRegion(const SkRegion& region) {
  1.1749 +    fWriter.writeRegion(region);
  1.1750 +}
  1.1751 +
  1.1752 +void SkPictureRecord::addText(const void* text, size_t byteLength) {
  1.1753 +#ifdef SK_DEBUG_SIZE
  1.1754 +    size_t start = fWriter.bytesWritten();
  1.1755 +#endif
  1.1756 +    addInt(byteLength);
  1.1757 +    fWriter.writePad(text, byteLength);
  1.1758 +#ifdef SK_DEBUG_SIZE
  1.1759 +    fTextBytes += fWriter.bytesWritten() - start;
  1.1760 +    fTextWrites++;
  1.1761 +#endif
  1.1762 +}
  1.1763 +
  1.1764 +///////////////////////////////////////////////////////////////////////////////
  1.1765 +
  1.1766 +#ifdef SK_DEBUG_SIZE
  1.1767 +size_t SkPictureRecord::size() const {
  1.1768 +    size_t result = 0;
  1.1769 +    size_t sizeData;
  1.1770 +    bitmaps(&sizeData);
  1.1771 +    result += sizeData;
  1.1772 +    matrices(&sizeData);
  1.1773 +    result += sizeData;
  1.1774 +    paints(&sizeData);
  1.1775 +    result += sizeData;
  1.1776 +    paths(&sizeData);
  1.1777 +    result += sizeData;
  1.1778 +    pictures(&sizeData);
  1.1779 +    result += sizeData;
  1.1780 +    regions(&sizeData);
  1.1781 +    result += sizeData;
  1.1782 +    result += streamlen();
  1.1783 +    return result;
  1.1784 +}
  1.1785 +
  1.1786 +int SkPictureRecord::bitmaps(size_t* size) const {
  1.1787 +    size_t result = 0;
  1.1788 +    int count = fBitmaps.count();
  1.1789 +    for (int index = 0; index < count; index++)
  1.1790 +        result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
  1.1791 +    *size = result;
  1.1792 +    return count;
  1.1793 +}
  1.1794 +
  1.1795 +int SkPictureRecord::matrices(size_t* size) const {
  1.1796 +    int count = fMatrices.count();
  1.1797 +    *size = sizeof(fMatrices[0]) * count;
  1.1798 +    return count;
  1.1799 +}
  1.1800 +
  1.1801 +int SkPictureRecord::paints(size_t* size) const {
  1.1802 +    size_t result = 0;
  1.1803 +    int count = fPaints.count();
  1.1804 +    for (int index = 0; index < count; index++)
  1.1805 +        result += sizeof(fPaints[index]) + fPaints[index]->size();
  1.1806 +    *size = result;
  1.1807 +    return count;
  1.1808 +}
  1.1809 +
  1.1810 +int SkPictureRecord::paths(size_t* size) const {
  1.1811 +    size_t result = 0;
  1.1812 +    int count = fPaths.count();
  1.1813 +    for (int index = 0; index < count; index++)
  1.1814 +        result += sizeof(fPaths[index]) + fPaths[index]->size();
  1.1815 +    *size = result;
  1.1816 +    return count;
  1.1817 +}
  1.1818 +
  1.1819 +int SkPictureRecord::regions(size_t* size) const {
  1.1820 +    size_t result = 0;
  1.1821 +    int count = fRegions.count();
  1.1822 +    for (int index = 0; index < count; index++)
  1.1823 +        result += sizeof(fRegions[index]) + fRegions[index]->size();
  1.1824 +    *size = result;
  1.1825 +    return count;
  1.1826 +}
  1.1827 +
  1.1828 +size_t SkPictureRecord::streamlen() const {
  1.1829 +    return fWriter.size();
  1.1830 +}
  1.1831 +#endif
  1.1832 +
  1.1833 +#ifdef SK_DEBUG_VALIDATE
  1.1834 +void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const {
  1.1835 +    SkASSERT(fWriter.size() == initialOffset + size);
  1.1836 +
  1.1837 +    validateBitmaps();
  1.1838 +    validateMatrices();
  1.1839 +    validatePaints();
  1.1840 +    validatePaths();
  1.1841 +    validateRegions();
  1.1842 +}
  1.1843 +
  1.1844 +void SkPictureRecord::validateBitmaps() const {
  1.1845 +    int count = fBitmapHeap->count();
  1.1846 +    SkASSERT((unsigned) count < 0x1000);
  1.1847 +    for (int index = 0; index < count; index++) {
  1.1848 +        const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index);
  1.1849 +        SkASSERT(bitPtr);
  1.1850 +        bitPtr->validate();
  1.1851 +    }
  1.1852 +}
  1.1853 +
  1.1854 +void SkPictureRecord::validateMatrices() const {
  1.1855 +    int count = fMatrices.count();
  1.1856 +    SkASSERT((unsigned) count < 0x1000);
  1.1857 +    for (int index = 0; index < count; index++) {
  1.1858 +        const SkFlatData* matrix = fMatrices[index];
  1.1859 +        SkASSERT(matrix);
  1.1860 +//        matrix->validate();
  1.1861 +    }
  1.1862 +}
  1.1863 +
  1.1864 +void SkPictureRecord::validatePaints() const {
  1.1865 +    int count = fPaints.count();
  1.1866 +    SkASSERT((unsigned) count < 0x1000);
  1.1867 +    for (int index = 0; index < count; index++) {
  1.1868 +        const SkFlatData* paint = fPaints[index];
  1.1869 +        SkASSERT(paint);
  1.1870 +//            paint->validate();
  1.1871 +    }
  1.1872 +}
  1.1873 +
  1.1874 +void SkPictureRecord::validatePaths() const {
  1.1875 +    if (NULL == fPathHeap) {
  1.1876 +        return;
  1.1877 +    }
  1.1878 +
  1.1879 +    int count = fPathHeap->count();
  1.1880 +    SkASSERT((unsigned) count < 0x1000);
  1.1881 +    for (int index = 0; index < count; index++) {
  1.1882 +        const SkPath& path = (*fPathHeap)[index];
  1.1883 +        path.validate();
  1.1884 +    }
  1.1885 +}
  1.1886 +
  1.1887 +void SkPictureRecord::validateRegions() const {
  1.1888 +    int count = fRegions.count();
  1.1889 +    SkASSERT((unsigned) count < 0x1000);
  1.1890 +    for (int index = 0; index < count; index++) {
  1.1891 +        const SkFlatData* region = fRegions[index];
  1.1892 +        SkASSERT(region);
  1.1893 +//        region->validate();
  1.1894 +    }
  1.1895 +}
  1.1896 +#endif

mercurial