Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkPictureRecord.h"
      9 #include "SkTSearch.h"
     10 #include "SkPixelRef.h"
     11 #include "SkRRect.h"
     12 #include "SkBBoxHierarchy.h"
     13 #include "SkPictureStateTree.h"
     14 
     15 #define MIN_WRITER_SIZE 16384
     16 #define HEAP_BLOCK_SIZE 4096
     17 
     18 enum {
     19     // just need a value that save or getSaveCount would never return
     20     kNoInitialSave = -1,
     21 };
     22 
     23 SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) :
     24         INHERITED(device),
     25         fBoundingHierarchy(NULL),
     26         fStateTree(NULL),
     27         fFlattenableHeap(HEAP_BLOCK_SIZE),
     28         fMatrices(&fFlattenableHeap),
     29         fPaints(&fFlattenableHeap),
     30         fRegions(&fFlattenableHeap),
     31         fWriter(MIN_WRITER_SIZE),
     32         fRecordFlags(flags) {
     33 #ifdef SK_DEBUG_SIZE
     34     fPointBytes = fRectBytes = fTextBytes = 0;
     35     fPointWrites = fRectWrites = fTextWrites = 0;
     36 #endif
     37 
     38     fRestoreOffsetStack.setReserve(32);
     39 
     40     fBitmapHeap = SkNEW(SkBitmapHeap);
     41     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
     42     fPathHeap = NULL;   // lazy allocate
     43     fFirstSavedLayerIndex = kNoSavedLayerIndex;
     44 
     45     fInitialSaveCount = kNoInitialSave;
     46 }
     47 
     48 SkPictureRecord::~SkPictureRecord() {
     49     SkSafeUnref(fBitmapHeap);
     50     SkSafeUnref(fPathHeap);
     51     SkSafeUnref(fBoundingHierarchy);
     52     SkSafeUnref(fStateTree);
     53     fFlattenableHeap.setBitmapStorage(NULL);
     54     fPictureRefs.unrefAll();
     55 }
     56 
     57 ///////////////////////////////////////////////////////////////////////////////
     58 
     59 SkDevice* SkPictureRecord::setDevice(SkDevice* device) {
     60     SkASSERT(!"eeek, don't try to change the device on a recording canvas");
     61     return this->INHERITED::setDevice(device);
     62 }
     63 
     64 int SkPictureRecord::save(SaveFlags flags) {
     65     // record the offset to us, making it non-positive to distinguish a save
     66     // from a clip entry.
     67     fRestoreOffsetStack.push(-(int32_t)fWriter.size());
     68 
     69     addDraw(SAVE);
     70     addInt(flags);
     71 
     72     validate();
     73     return this->INHERITED::save(flags);
     74 }
     75 
     76 int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint,
     77                                SaveFlags flags) {
     78     // record the offset to us, making it non-positive to distinguish a save
     79     // from a clip entry.
     80     fRestoreOffsetStack.push(-(int32_t)fWriter.size());
     81 
     82     addDraw(SAVE_LAYER);
     83     addRectPtr(bounds);
     84     addPaintPtr(paint);
     85     addInt(flags);
     86 
     87     if (kNoSavedLayerIndex == fFirstSavedLayerIndex) {
     88         fFirstSavedLayerIndex = fRestoreOffsetStack.count();
     89     }
     90 
     91     validate();
     92     /*  Don't actually call saveLayer, because that will try to allocate an
     93         offscreen device (potentially very big) which we don't actually need
     94         at this time (and may not be able to afford since during record our
     95         clip starts out the size of the picture, which is often much larger
     96         than the size of the actual device we'll use during playback).
     97      */
     98     int count = this->INHERITED::save(flags);
     99     this->clipRectBounds(bounds, flags, NULL);
    100     return count;
    101 }
    102 
    103 bool SkPictureRecord::isDrawingToLayer() const {
    104     return fFirstSavedLayerIndex != kNoSavedLayerIndex;
    105 }
    106 
    107 // Return the size of the specified drawType's recorded block, or 0 if this verb
    108 // is variable sized, and therefore not known.
    109 static inline uint32_t getSkipableSize(unsigned drawType) {
    110     static const uint8_t gSizes[LAST_DRAWTYPE_ENUM + 1] = {
    111         0,  // UNUSED,
    112         4,  // CLIP_PATH,
    113         4,  // CLIP_REGION,
    114         7,  // CLIP_RECT,
    115         15, // CLIP_RRECT,
    116         2,  // CONCAT,
    117         0,  // DRAW_BITMAP,
    118         0,  // DRAW_BITMAP_MATRIX,
    119         0,  // DRAW_BITMAP_NINE,
    120         0,  // DRAW_BITMAP_RECT,
    121         0,  // DRAW_CLEAR,
    122         0,  // DRAW_DATA,
    123         0,  // DRAW_OVAL,
    124         0,  // DRAW_PAINT,
    125         0,  // DRAW_PATH,
    126         0,  // DRAW_PICTURE,
    127         0,  // DRAW_POINTS,
    128         0,  // DRAW_POS_TEXT,
    129         0,  // DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
    130         0,  // DRAW_POS_TEXT_H,
    131         0,  // DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
    132         0,  // DRAW_RECT,
    133         0,  // DRAW_RRECT,
    134         0,  // DRAW_SPRITE,
    135         0,  // DRAW_TEXT,
    136         0,  // DRAW_TEXT_ON_PATH,
    137         0,  // DRAW_TEXT_TOP_BOTTOM,   // fast variant of DRAW_TEXT
    138         0,  // DRAW_VERTICES,
    139         0,  // RESTORE,
    140         2,  // ROTATE,
    141         2,  // SAVE,
    142         0,  // SAVE_LAYER,
    143         3,  // SCALE,
    144         2,  // SET_MATRIX,
    145         3,  // SKEW,
    146         3,  // TRANSLATE,
    147     };
    148 
    149     SkASSERT(sizeof(gSizes) == LAST_DRAWTYPE_ENUM + 1);
    150     SkASSERT((unsigned)drawType <= (unsigned)LAST_DRAWTYPE_ENUM);
    151     return gSizes[drawType] * sizeof(uint32_t);
    152 }
    153 
    154 #ifdef TRACK_COLLAPSE_STATS
    155     static int gCollapseCount, gCollapseCalls;
    156 #endif
    157 
    158 /*
    159  *  Restore has just been called (but not recoreded), so look back at the
    160  *  matching save(), and see if we can eliminate the pair of them, due to no
    161  *  intervening matrix/clip calls.
    162  *
    163  *  If so, update the writer and return true, in which case we won't even record
    164  *  the restore() call. If we still need the restore(), return false.
    165  */
    166 static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) {
    167 #ifdef TRACK_COLLAPSE_STATS
    168     gCollapseCalls += 1;
    169 #endif
    170 
    171     int32_t restoreOffset = (int32_t)writer->size();
    172 
    173     // back up to the save block
    174     while (offset > 0) {
    175         offset = *writer->peek32(offset);
    176     }
    177 
    178     // now offset points to a save
    179     offset = -offset;
    180     if (SAVE_LAYER == *writer->peek32(offset)) {
    181         // not ready to cull these out yet (mrr)
    182         return false;
    183     }
    184     SkASSERT(SAVE == *writer->peek32(offset));
    185 
    186     // Walk forward until we get back to either a draw-verb (abort) or we hit
    187     // our restore (success).
    188     int32_t saveOffset = offset;
    189 
    190     offset += getSkipableSize(SAVE);
    191     while (offset < restoreOffset) {
    192         uint32_t* block = writer->peek32(offset);
    193         uint32_t op = *block;
    194         uint32_t opSize = getSkipableSize(op);
    195         if (0 == opSize) {
    196             // drawing verb, abort
    197             return false;
    198         }
    199         offset += opSize;
    200     }
    201 
    202 #ifdef TRACK_COLLAPSE_STATS
    203     gCollapseCount += 1;
    204     SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls,
    205              (double)gCollapseCount / gCollapseCalls, "%");
    206 #endif
    207 
    208     writer->rewindToOffset(saveOffset);
    209     return true;
    210 }
    211 
    212 void SkPictureRecord::restore() {
    213     // FIXME: SkDeferredCanvas needs to be refactored to respect
    214     // save/restore balancing so that the following test can be
    215     // turned on permanently.
    216 #if 0
    217     SkASSERT(fRestoreOffsetStack.count() > 1);
    218 #endif
    219 
    220     // check for underflow
    221     if (fRestoreOffsetStack.count() == 0) {
    222         return;
    223     }
    224 
    225     if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) {
    226         fFirstSavedLayerIndex = kNoSavedLayerIndex;
    227     }
    228 
    229     if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) {
    230         fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size());
    231         this->addDraw(RESTORE);
    232     }
    233 
    234     fRestoreOffsetStack.pop();
    235 
    236     validate();
    237     return this->INHERITED::restore();
    238 }
    239 
    240 bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) {
    241     addDraw(TRANSLATE);
    242     addScalar(dx);
    243     addScalar(dy);
    244     validate();
    245     return this->INHERITED::translate(dx, dy);
    246 }
    247 
    248 bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) {
    249     addDraw(SCALE);
    250     addScalar(sx);
    251     addScalar(sy);
    252     validate();
    253     return this->INHERITED::scale(sx, sy);
    254 }
    255 
    256 bool SkPictureRecord::rotate(SkScalar degrees) {
    257     addDraw(ROTATE);
    258     addScalar(degrees);
    259     validate();
    260     return this->INHERITED::rotate(degrees);
    261 }
    262 
    263 bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) {
    264     addDraw(SKEW);
    265     addScalar(sx);
    266     addScalar(sy);
    267     validate();
    268     return this->INHERITED::skew(sx, sy);
    269 }
    270 
    271 bool SkPictureRecord::concat(const SkMatrix& matrix) {
    272     validate();
    273     addDraw(CONCAT);
    274     addMatrix(matrix);
    275     validate();
    276     return this->INHERITED::concat(matrix);
    277 }
    278 
    279 void SkPictureRecord::setMatrix(const SkMatrix& matrix) {
    280     validate();
    281     addDraw(SET_MATRIX);
    282     addMatrix(matrix);
    283     validate();
    284     this->INHERITED::setMatrix(matrix);
    285 }
    286 
    287 static bool regionOpExpands(SkRegion::Op op) {
    288     switch (op) {
    289         case SkRegion::kUnion_Op:
    290         case SkRegion::kXOR_Op:
    291         case SkRegion::kReverseDifference_Op:
    292         case SkRegion::kReplace_Op:
    293             return true;
    294         case SkRegion::kIntersect_Op:
    295         case SkRegion::kDifference_Op:
    296             return false;
    297         default:
    298             SkDEBUGFAIL("unknown region op");
    299             return false;
    300     }
    301 }
    302 
    303 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(
    304     uint32_t restoreOffset) {
    305     int32_t offset = fRestoreOffsetStack.top();
    306     while (offset > 0) {
    307         uint32_t* peek = fWriter.peek32(offset);
    308         offset = *peek;
    309         *peek = restoreOffset;
    310     }
    311 
    312 #ifdef SK_DEBUG
    313     // assert that the final offset value points to a save verb
    314     uint32_t drawOp = *fWriter.peek32(-offset);
    315     SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
    316 #endif
    317 }
    318 
    319 void SkPictureRecord::beginRecording() {
    320     // we have to call this *after* our constructor, to ensure that it gets
    321     // recorded. This is balanced by restoreToCount() call from endRecording,
    322     // which in-turn calls our overridden restore(), so those get recorded too.
    323     fInitialSaveCount = this->save(kMatrixClip_SaveFlag);
    324 }
    325 
    326 void SkPictureRecord::endRecording() {
    327     SkASSERT(kNoInitialSave != fInitialSaveCount);
    328     this->restoreToCount(fInitialSaveCount);
    329 }
    330 
    331 void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
    332     if (fRestoreOffsetStack.isEmpty()) {
    333         return;
    334     }
    335 
    336     if (regionOpExpands(op)) {
    337         // Run back through any previous clip ops, and mark their offset to
    338         // be 0, disabling their ability to trigger a jump-to-restore, otherwise
    339         // they could hide this clips ability to expand the clip (i.e. go from
    340         // empty to non-empty).
    341         fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
    342     }
    343 
    344     size_t offset = fWriter.size();
    345     // The RestoreOffset field is initially filled with a placeholder
    346     // value that points to the offset of the previous RestoreOffset
    347     // in the current stack level, thus forming a linked list so that
    348     // the restore offsets can be filled in when the corresponding
    349     // restore command is recorded.
    350     addInt(fRestoreOffsetStack.top());
    351     fRestoreOffsetStack.top() = offset;
    352 }
    353 
    354 bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
    355     addDraw(CLIP_RECT);
    356     addRect(rect);
    357     addInt(ClipParams_pack(op, doAA));
    358     recordRestoreOffsetPlaceholder(op);
    359 
    360     validate();
    361     return this->INHERITED::clipRect(rect, op, doAA);
    362 }
    363 
    364 bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
    365     if (rrect.isRect()) {
    366         return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA);
    367     }
    368 
    369     addDraw(CLIP_RRECT);
    370     addRRect(rrect);
    371     addInt(ClipParams_pack(op, doAA));
    372     recordRestoreOffsetPlaceholder(op);
    373 
    374     validate();
    375 
    376     if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
    377         return this->INHERITED::clipRect(rrect.getBounds(), op, doAA);
    378     } else {
    379         return this->INHERITED::clipRRect(rrect, op, doAA);
    380     }
    381 }
    382 
    383 bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
    384 
    385     SkRect r;
    386     if (!path.isInverseFillType() && path.isRect(&r)) {
    387         return this->clipRect(r, op, doAA);
    388     }
    389 
    390     addDraw(CLIP_PATH);
    391     addPath(path);
    392     addInt(ClipParams_pack(op, doAA));
    393     recordRestoreOffsetPlaceholder(op);
    394 
    395     validate();
    396 
    397     if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) {
    398         return this->INHERITED::clipRect(path.getBounds(), op, doAA);
    399     } else {
    400         return this->INHERITED::clipPath(path, op, doAA);
    401     }
    402 }
    403 
    404 bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) {
    405     addDraw(CLIP_REGION);
    406     addRegion(region);
    407     addInt(ClipParams_pack(op, false));
    408     recordRestoreOffsetPlaceholder(op);
    409 
    410     validate();
    411     return this->INHERITED::clipRegion(region, op);
    412 }
    413 
    414 void SkPictureRecord::clear(SkColor color) {
    415     addDraw(DRAW_CLEAR);
    416     addInt(color);
    417     validate();
    418 }
    419 
    420 void SkPictureRecord::drawPaint(const SkPaint& paint) {
    421     addDraw(DRAW_PAINT);
    422     addPaint(paint);
    423     validate();
    424 }
    425 
    426 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[],
    427                         const SkPaint& paint) {
    428     addDraw(DRAW_POINTS);
    429     addPaint(paint);
    430     addInt(mode);
    431     addInt(count);
    432     fWriter.writeMul4(pts, count * sizeof(SkPoint));
    433     validate();
    434 }
    435 
    436 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) {
    437     addDraw(DRAW_OVAL);
    438     addPaint(paint);
    439     addRect(oval);
    440     validate();
    441 }
    442 
    443 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) {
    444     addDraw(DRAW_RECT);
    445     addPaint(paint);
    446     addRect(rect);
    447     validate();
    448 }
    449 
    450 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
    451     if (rrect.isRect()) {
    452         addDraw(DRAW_RECT);
    453         addPaint(paint);
    454         addRect(rrect.getBounds());
    455     } else if (rrect.isOval()) {
    456         addDraw(DRAW_OVAL);
    457         addPaint(paint);
    458         addRect(rrect.getBounds());
    459     } else {
    460         addDraw(DRAW_RRECT);
    461         addPaint(paint);
    462         addRRect(rrect);
    463     }
    464     validate();
    465 }
    466 
    467 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) {
    468     addDraw(DRAW_PATH);
    469     addPaint(paint);
    470     addPath(path);
    471     validate();
    472 }
    473 
    474 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
    475                         const SkPaint* paint = NULL) {
    476     addDraw(DRAW_BITMAP);
    477     addPaintPtr(paint);
    478     addBitmap(bitmap);
    479     addScalar(left);
    480     addScalar(top);
    481     validate();
    482 }
    483 
    484 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
    485                             const SkRect& dst, const SkPaint* paint) {
    486     addDraw(DRAW_BITMAP_RECT_TO_RECT);
    487     addPaintPtr(paint);
    488     addBitmap(bitmap);
    489     addRectPtr(src);  // may be null
    490     addRect(dst);
    491     validate();
    492 }
    493 
    494 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix,
    495                                        const SkPaint* paint) {
    496     addDraw(DRAW_BITMAP_MATRIX);
    497     addPaintPtr(paint);
    498     addBitmap(bitmap);
    499     addMatrix(matrix);
    500     validate();
    501 }
    502 
    503 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
    504                                      const SkRect& dst, const SkPaint* paint) {
    505     addDraw(DRAW_BITMAP_NINE);
    506     addPaintPtr(paint);
    507     addBitmap(bitmap);
    508     addIRect(center);
    509     addRect(dst);
    510     validate();
    511 }
    512 
    513 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top,
    514                         const SkPaint* paint = NULL) {
    515     addDraw(DRAW_SPRITE);
    516     addPaintPtr(paint);
    517     addBitmap(bitmap);
    518     addInt(left);
    519     addInt(top);
    520     validate();
    521 }
    522 
    523 // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
    524 // tweaked by paint.computeFastBounds().
    525 //
    526 static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) {
    527     SkPaint::FontMetrics metrics;
    528     paint.getFontMetrics(&metrics);
    529     SkRect bounds;
    530     // construct a rect so we can see any adjustments from the paint.
    531     // we use 0,1 for left,right, just so the rect isn't empty
    532     bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom);
    533     (void)paint.computeFastBounds(bounds, &bounds);
    534     topbot[0] = bounds.fTop;
    535     topbot[1] = bounds.fBottom;
    536 }
    537 
    538 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat,
    539                                               SkScalar minY, SkScalar maxY) {
    540     if (!flat.isTopBotWritten()) {
    541         computeFontMetricsTopBottom(paint, flat.writableTopBot());
    542         SkASSERT(flat.isTopBotWritten());
    543     }
    544     addScalar(flat.topBot()[0] + minY);
    545     addScalar(flat.topBot()[1] + maxY);
    546 }
    547 
    548 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x,
    549                       SkScalar y, const SkPaint& paint) {
    550     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
    551 
    552     addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT);
    553     const SkFlatData* flatPaintData = addPaint(paint);
    554     SkASSERT(flatPaintData);
    555     addText(text, byteLength);
    556     addScalar(x);
    557     addScalar(y);
    558     if (fast) {
    559         addFontMetricsTopBottom(paint, *flatPaintData, y, y);
    560     }
    561     validate();
    562 }
    563 
    564 void SkPictureRecord::drawPosText(const void* text, size_t byteLength,
    565                          const SkPoint pos[], const SkPaint& paint) {
    566     size_t points = paint.countText(text, byteLength);
    567     if (0 == points)
    568         return;
    569 
    570     bool canUseDrawH = true;
    571     SkScalar minY = pos[0].fY;
    572     SkScalar maxY = pos[0].fY;
    573     // check if the caller really should have used drawPosTextH()
    574     {
    575         const SkScalar firstY = pos[0].fY;
    576         for (size_t index = 1; index < points; index++) {
    577             if (pos[index].fY != firstY) {
    578                 canUseDrawH = false;
    579                 if (pos[index].fY < minY) {
    580                     minY = pos[index].fY;
    581                 } else if (pos[index].fY > maxY) {
    582                     maxY = pos[index].fY;
    583                 }
    584             }
    585         }
    586     }
    587 
    588     bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds();
    589     bool fast = canUseDrawH && fastBounds;
    590 
    591     if (fast) {
    592         addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
    593     } else if (canUseDrawH) {
    594         addDraw(DRAW_POS_TEXT_H);
    595     } else if (fastBounds) {
    596         addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
    597     } else {
    598         addDraw(DRAW_POS_TEXT);
    599     }
    600     const SkFlatData* flatPaintData = addPaint(paint);
    601     SkASSERT(flatPaintData);
    602     addText(text, byteLength);
    603     addInt(points);
    604 
    605 #ifdef SK_DEBUG_SIZE
    606     size_t start = fWriter.size();
    607 #endif
    608     if (canUseDrawH) {
    609         if (fast) {
    610             addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY);
    611         }
    612         addScalar(pos[0].fY);
    613         SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
    614         for (size_t index = 0; index < points; index++)
    615             *xptr++ = pos[index].fX;
    616     }
    617     else {
    618         fWriter.writeMul4(pos, points * sizeof(SkPoint));
    619         if (fastBounds) {
    620             addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY);
    621         }
    622     }
    623 #ifdef SK_DEBUG_SIZE
    624     fPointBytes += fWriter.size() - start;
    625     fPointWrites += points;
    626 #endif
    627     validate();
    628 }
    629 
    630 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength,
    631                           const SkScalar xpos[], SkScalar constY,
    632                           const SkPaint& paint) {
    633     size_t points = paint.countText(text, byteLength);
    634     if (0 == points)
    635         return;
    636 
    637     bool fast = !paint.isVerticalText() && paint.canComputeFastBounds();
    638 
    639     addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H);
    640     const SkFlatData* flatPaintData = addPaint(paint);
    641     SkASSERT(flatPaintData);
    642     addText(text, byteLength);
    643     addInt(points);
    644 
    645 #ifdef SK_DEBUG_SIZE
    646     size_t start = fWriter.size();
    647 #endif
    648     if (fast) {
    649         addFontMetricsTopBottom(paint, *flatPaintData, constY, constY);
    650     }
    651     addScalar(constY);
    652     fWriter.writeMul4(xpos, points * sizeof(SkScalar));
    653 #ifdef SK_DEBUG_SIZE
    654     fPointBytes += fWriter.size() - start;
    655     fPointWrites += points;
    656 #endif
    657     validate();
    658 }
    659 
    660 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength,
    661                             const SkPath& path, const SkMatrix* matrix,
    662                             const SkPaint& paint) {
    663     addDraw(DRAW_TEXT_ON_PATH);
    664     addPaint(paint);
    665     addText(text, byteLength);
    666     addPath(path);
    667     addMatrixPtr(matrix);
    668     validate();
    669 }
    670 
    671 void SkPictureRecord::drawPicture(SkPicture& picture) {
    672     addDraw(DRAW_PICTURE);
    673     addPicture(picture);
    674     validate();
    675 }
    676 
    677 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount,
    678                           const SkPoint vertices[], const SkPoint texs[],
    679                           const SkColor colors[], SkXfermode*,
    680                           const uint16_t indices[], int indexCount,
    681                           const SkPaint& paint) {
    682     uint32_t flags = 0;
    683     if (texs) {
    684         flags |= DRAW_VERTICES_HAS_TEXS;
    685     }
    686     if (colors) {
    687         flags |= DRAW_VERTICES_HAS_COLORS;
    688     }
    689     if (indexCount > 0) {
    690         flags |= DRAW_VERTICES_HAS_INDICES;
    691     }
    692 
    693     addDraw(DRAW_VERTICES);
    694     addPaint(paint);
    695     addInt(flags);
    696     addInt(vmode);
    697     addInt(vertexCount);
    698     addPoints(vertices, vertexCount);
    699     if (flags & DRAW_VERTICES_HAS_TEXS) {
    700         addPoints(texs, vertexCount);
    701     }
    702     if (flags & DRAW_VERTICES_HAS_COLORS) {
    703         fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
    704     }
    705     if (flags & DRAW_VERTICES_HAS_INDICES) {
    706         addInt(indexCount);
    707         fWriter.writePad(indices, indexCount * sizeof(uint16_t));
    708     }
    709 }
    710 
    711 void SkPictureRecord::drawData(const void* data, size_t length) {
    712     addDraw(DRAW_DATA);
    713     addInt(length);
    714     fWriter.writePad(data, length);
    715 }
    716 
    717 ///////////////////////////////////////////////////////////////////////////////
    718 
    719 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
    720     const int index = fBitmapHeap->insert(bitmap);
    721     // In debug builds, a bad return value from insert() will crash, allowing for debugging. In
    722     // release builds, the invalid value will be recorded so that the reader will know that there
    723     // was a problem.
    724     SkASSERT(index != SkBitmapHeap::INVALID_SLOT);
    725     addInt(index);
    726 }
    727 
    728 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
    729     addMatrixPtr(&matrix);
    730 }
    731 
    732 void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) {
    733     this->addInt(matrix ? fMatrices.find(*matrix) : 0);
    734 }
    735 
    736 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) {
    737     const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL;
    738     int index = data ? data->index() : 0;
    739     this->addInt(index);
    740     return data;
    741 }
    742 
    743 void SkPictureRecord::addPath(const SkPath& path) {
    744     if (NULL == fPathHeap) {
    745         fPathHeap = SkNEW(SkPathHeap);
    746     }
    747     addInt(fPathHeap->append(path));
    748 }
    749 
    750 void SkPictureRecord::addPicture(SkPicture& picture) {
    751     int index = fPictureRefs.find(&picture);
    752     if (index < 0) {    // not found
    753         index = fPictureRefs.count();
    754         *fPictureRefs.append() = &picture;
    755         picture.ref();
    756     }
    757     // follow the convention of recording a 1-based index
    758     addInt(index + 1);
    759 }
    760 
    761 void SkPictureRecord::addPoint(const SkPoint& point) {
    762 #ifdef SK_DEBUG_SIZE
    763     size_t start = fWriter.size();
    764 #endif
    765     fWriter.writePoint(point);
    766 #ifdef SK_DEBUG_SIZE
    767     fPointBytes += fWriter.size() - start;
    768     fPointWrites++;
    769 #endif
    770 }
    771 
    772 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
    773     fWriter.writeMul4(pts, count * sizeof(SkPoint));
    774 #ifdef SK_DEBUG_SIZE
    775     fPointBytes += count * sizeof(SkPoint);
    776     fPointWrites++;
    777 #endif
    778 }
    779 
    780 void SkPictureRecord::addRect(const SkRect& rect) {
    781 #ifdef SK_DEBUG_SIZE
    782     size_t start = fWriter.size();
    783 #endif
    784     fWriter.writeRect(rect);
    785 #ifdef SK_DEBUG_SIZE
    786     fRectBytes += fWriter.size() - start;
    787     fRectWrites++;
    788 #endif
    789 }
    790 
    791 void SkPictureRecord::addRectPtr(const SkRect* rect) {
    792     if (fWriter.writeBool(rect != NULL)) {
    793         fWriter.writeRect(*rect);
    794     }
    795 }
    796 
    797 void SkPictureRecord::addIRect(const SkIRect& rect) {
    798     fWriter.write(&rect, sizeof(rect));
    799 }
    800 
    801 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
    802     if (fWriter.writeBool(rect != NULL)) {
    803         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
    804     }
    805 }
    806 
    807 void SkPictureRecord::addRRect(const SkRRect& rrect) {
    808     fWriter.writeRRect(rrect);
    809 }
    810 
    811 void SkPictureRecord::addRegion(const SkRegion& region) {
    812     addInt(fRegions.find(region));
    813 }
    814 
    815 void SkPictureRecord::addText(const void* text, size_t byteLength) {
    816 #ifdef SK_DEBUG_SIZE
    817     size_t start = fWriter.size();
    818 #endif
    819     addInt(byteLength);
    820     fWriter.writePad(text, byteLength);
    821 #ifdef SK_DEBUG_SIZE
    822     fTextBytes += fWriter.size() - start;
    823     fTextWrites++;
    824 #endif
    825 }
    826 
    827 ///////////////////////////////////////////////////////////////////////////////
    828 
    829 #ifdef SK_DEBUG_SIZE
    830 size_t SkPictureRecord::size() const {
    831     size_t result = 0;
    832     size_t sizeData;
    833     bitmaps(&sizeData);
    834     result += sizeData;
    835     matrices(&sizeData);
    836     result += sizeData;
    837     paints(&sizeData);
    838     result += sizeData;
    839     paths(&sizeData);
    840     result += sizeData;
    841     pictures(&sizeData);
    842     result += sizeData;
    843     regions(&sizeData);
    844     result += sizeData;
    845     result += streamlen();
    846     return result;
    847 }
    848 
    849 int SkPictureRecord::bitmaps(size_t* size) const {
    850     size_t result = 0;
    851     int count = fBitmaps.count();
    852     for (int index = 0; index < count; index++)
    853         result += sizeof(fBitmaps[index]) + fBitmaps[index]->size();
    854     *size = result;
    855     return count;
    856 }
    857 
    858 int SkPictureRecord::matrices(size_t* size) const {
    859     int count = fMatrices.count();
    860     *size = sizeof(fMatrices[0]) * count;
    861     return count;
    862 }
    863 
    864 int SkPictureRecord::paints(size_t* size) const {
    865     size_t result = 0;
    866     int count = fPaints.count();
    867     for (int index = 0; index < count; index++)
    868         result += sizeof(fPaints[index]) + fPaints[index]->size();
    869     *size = result;
    870     return count;
    871 }
    872 
    873 int SkPictureRecord::paths(size_t* size) const {
    874     size_t result = 0;
    875     int count = fPaths.count();
    876     for (int index = 0; index < count; index++)
    877         result += sizeof(fPaths[index]) + fPaths[index]->size();
    878     *size = result;
    879     return count;
    880 }
    881 
    882 int SkPictureRecord::regions(size_t* size) const {
    883     size_t result = 0;
    884     int count = fRegions.count();
    885     for (int index = 0; index < count; index++)
    886         result += sizeof(fRegions[index]) + fRegions[index]->size();
    887     *size = result;
    888     return count;
    889 }
    890 
    891 size_t SkPictureRecord::streamlen() const {
    892     return fWriter.size();
    893 }
    894 #endif
    895 
    896 #ifdef SK_DEBUG_VALIDATE
    897 void SkPictureRecord::validate() const {
    898     validateBitmaps();
    899     validateMatrices();
    900     validatePaints();
    901     validatePaths();
    902     validatePictures();
    903     validateRegions();
    904 }
    905 
    906 void SkPictureRecord::validateBitmaps() const {
    907     int count = fBitmaps.count();
    908     SkASSERT((unsigned) count < 0x1000);
    909     for (int index = 0; index < count; index++) {
    910         const SkFlatBitmap* bitPtr = fBitmaps[index];
    911         SkASSERT(bitPtr);
    912         bitPtr->validate();
    913     }
    914 }
    915 
    916 void SkPictureRecord::validateMatrices() const {
    917     int count = fMatrices.count();
    918     SkASSERT((unsigned) count < 0x1000);
    919     for (int index = 0; index < count; index++) {
    920         const SkFlatMatrix* matrix = fMatrices[index];
    921         SkASSERT(matrix);
    922         matrix->validate();
    923     }
    924 }
    925 
    926 void SkPictureRecord::validatePaints() const {
    927     int count = fPaints.count();
    928     SkASSERT((unsigned) count < 0x1000);
    929     for (int index = 0; index < count; index++) {
    930         const SkFlatPaint* paint = fPaints[index];
    931         SkASSERT(paint);
    932 //            paint->validate();
    933     }
    934 }
    935 
    936 void SkPictureRecord::validatePaths() const {
    937     int count = fPaths.count();
    938     SkASSERT((unsigned) count < 0x1000);
    939     for (int index = 0; index < count; index++) {
    940         const SkFlatPath* path = fPaths[index];
    941         SkASSERT(path);
    942         path->validate();
    943     }
    944 }
    945 
    946 void SkPictureRecord::validateRegions() const {
    947     int count = fRegions.count();
    948     SkASSERT((unsigned) count < 0x1000);
    949     for (int index = 0; index < count; index++) {
    950         const SkFlatRegion* region = fRegions[index];
    951         SkASSERT(region);
    952         region->validate();
    953     }
    954 }
    955 #endif
    956