Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkPictureRecord.h"
      9 #include "SkDevice.h"
     10 #include "SkImage_Base.h"
     11 #include "SkPatchUtils.h"
     12 #include "SkPixelRef.h"
     13 #include "SkRRect.h"
     14 #include "SkTextBlob.h"
     15 #include "SkTSearch.h"
     16 
     17 #define HEAP_BLOCK_SIZE 4096
     18 
     19 enum {
     20     // just need a value that save or getSaveCount would never return
     21     kNoInitialSave = -1,
     22 };
     23 
     24 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
     25 static int const kUInt32Size = 4;
     26 
     27 static const uint32_t kSaveSize = kUInt32Size;
     28 #ifdef SK_DEBUG
     29 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size;
     30 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect);
     31 #endif//SK_DEBUG
     32 
     33 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
     34     : INHERITED(dimensions.width(), dimensions.height())
     35     , fRecordFlags(flags)
     36     , fInitialSaveCount(kNoInitialSave) {
     37 }
     38 
     39 SkPictureRecord::~SkPictureRecord() {
     40     fPictureRefs.unrefAll();
     41     fTextBlobRefs.unrefAll();
     42 }
     43 
     44 ///////////////////////////////////////////////////////////////////////////////
     45 
     46 #ifdef SK_DEBUG
     47 // Return the offset of the paint inside a given op's byte stream. A zero
     48 // return value means there is no paint (and you really shouldn't be calling
     49 // this method)
     50 static inline size_t get_paint_offset(DrawType op, size_t opSize) {
     51     // These offsets are where the paint would be if the op size doesn't overflow
     52     static const uint8_t gPaintOffsets[] = {
     53         0,  // UNUSED - no paint
     54         0,  // CLIP_PATH - no paint
     55         0,  // CLIP_REGION - no paint
     56         0,  // CLIP_RECT - no paint
     57         0,  // CLIP_RRECT - no paint
     58         0,  // CONCAT - no paint
     59         1,  // DRAW_BITMAP - right after op code
     60         1,  // DRAW_BITMAP_MATRIX - right after op code, deprecated
     61         1,  // DRAW_BITMAP_NINE - right after op code
     62         1,  // DRAW_BITMAP_RECT_TO_RECT - right after op code
     63         0,  // DRAW_CLEAR - no paint
     64         0,  // DRAW_DATA - no paint
     65         1,  // DRAW_OVAL - right after op code
     66         1,  // DRAW_PAINT - right after op code
     67         1,  // DRAW_PATH - right after op code
     68         0,  // DRAW_PICTURE - no paint
     69         1,  // DRAW_POINTS - right after op code
     70         1,  // DRAW_POS_TEXT - right after op code
     71         1,  // DRAW_POS_TEXT_TOP_BOTTOM - right after op code
     72         1,  // DRAW_POS_TEXT_H - right after op code
     73         1,  // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code
     74         1,  // DRAW_RECT - right after op code
     75         1,  // DRAW_RRECT - right after op code
     76         1,  // DRAW_SPRITE - right after op code
     77         1,  // DRAW_TEXT - right after op code
     78         1,  // DRAW_TEXT_ON_PATH - right after op code
     79         1,  // DRAW_TEXT_TOP_BOTTOM - right after op code
     80         1,  // DRAW_VERTICES - right after op code
     81         0,  // RESTORE - no paint
     82         0,  // ROTATE - no paint
     83         0,  // SAVE - no paint
     84         0,  // SAVE_LAYER - see below - this paint's location varies
     85         0,  // SCALE - no paint
     86         0,  // SET_MATRIX - no paint
     87         0,  // SKEW - no paint
     88         0,  // TRANSLATE - no paint
     89         0,  // NOOP - no paint
     90         0,  // BEGIN_GROUP - no paint
     91         0,  // COMMENT - no paint
     92         0,  // END_GROUP - no paint
     93         1,  // DRAWDRRECT - right after op code
     94         0,  // PUSH_CULL - no paint
     95         0,  // POP_CULL - no paint
     96         1,  // DRAW_PATCH - right after op code
     97         1,  // DRAW_PICTURE_MATRIX_PAINT - right after op code
     98         1,  // DRAW_TEXT_BLOB- right after op code
     99     };
    100 
    101     SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1,
    102                       need_to_be_in_sync);
    103     SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM);
    104 
    105     int overflow = 0;
    106     if (0 != (opSize & ~MASK_24) || opSize == MASK_24) {
    107         // This op's size overflows so an extra uint32_t will be written
    108         // after the op code
    109         overflow = sizeof(uint32_t);
    110     }
    111 
    112     if (SAVE_LAYER == op) {
    113         static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size;
    114         static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect);
    115 
    116         if (kSaveLayerNoBoundsSize == opSize) {
    117             return kSaveLayerNoBoundsPaintOffset + overflow;
    118         } else {
    119             SkASSERT(kSaveLayerWithBoundsSize == opSize);
    120             return kSaveLayerWithBoundsPaintOffset + overflow;
    121         }
    122     }
    123 
    124     SkASSERT(0 != gPaintOffsets[op]);   // really shouldn't be calling this method
    125     return gPaintOffsets[op] * sizeof(uint32_t) + overflow;
    126 }
    127 #endif//SK_DEBUG
    128 
    129 void SkPictureRecord::willSave() {
    130     // record the offset to us, making it non-positive to distinguish a save
    131     // from a clip entry.
    132     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
    133     this->recordSave();
    134 
    135     this->INHERITED::willSave();
    136 }
    137 
    138 void SkPictureRecord::recordSave() {
    139     fContentInfo.onSave();
    140 
    141     // op only
    142     size_t size = kSaveSize;
    143     size_t initialOffset = this->addDraw(SAVE, &size);
    144 
    145     this->validate(initialOffset, size);
    146 }
    147 
    148 SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds,
    149                                                            const SkPaint* paint, SaveFlags flags) {
    150     // record the offset to us, making it non-positive to distinguish a save
    151     // from a clip entry.
    152     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
    153     this->recordSaveLayer(bounds, paint, flags);
    154 
    155     this->INHERITED::willSaveLayer(bounds, paint, flags);
    156     /*  No need for a (potentially very big) layer which we don't actually need
    157         at this time (and may not be able to afford since during record our
    158         clip starts out the size of the picture, which is often much larger
    159         than the size of the actual device we'll use during playback).
    160      */
    161     return kNoLayer_SaveLayerStrategy;
    162 }
    163 
    164 void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint,
    165                                       SaveFlags flags) {
    166     fContentInfo.onSaveLayer();
    167 
    168     // op + bool for 'bounds'
    169     size_t size = 2 * kUInt32Size;
    170     if (bounds) {
    171         size += sizeof(*bounds); // + rect
    172     }
    173     // + paint index + flags
    174     size += 2 * kUInt32Size;
    175 
    176     SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size);
    177 
    178     size_t initialOffset = this->addDraw(SAVE_LAYER, &size);
    179     this->addRectPtr(bounds);
    180     SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten());
    181     this->addPaintPtr(paint);
    182     this->addInt(flags);
    183 
    184     this->validate(initialOffset, size);
    185 }
    186 
    187 #ifdef SK_DEBUG
    188 /*
    189  * Read the op code from 'offset' in 'writer' and extract the size too.
    190  */
    191 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
    192     uint32_t peek = writer->readTAt<uint32_t>(offset);
    193 
    194     uint32_t op;
    195     UNPACK_8_24(peek, op, *size);
    196     if (MASK_24 == *size) {
    197         // size required its own slot right after the op code
    198         *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
    199     }
    200     return (DrawType) op;
    201 }
    202 #endif//SK_DEBUG
    203 
    204 void SkPictureRecord::willRestore() {
    205     // FIXME: SkDeferredCanvas needs to be refactored to respect
    206     // save/restore balancing so that the following test can be
    207     // turned on permanently.
    208 #if 0
    209     SkASSERT(fRestoreOffsetStack.count() > 1);
    210 #endif
    211 
    212     // check for underflow
    213     if (fRestoreOffsetStack.count() == 0) {
    214         return;
    215     }
    216 
    217     this->recordRestore();
    218 
    219     fRestoreOffsetStack.pop();
    220 
    221     this->INHERITED::willRestore();
    222 }
    223 
    224 void SkPictureRecord::recordRestore(bool fillInSkips) {
    225     fContentInfo.onRestore();
    226 
    227     if (fillInSkips) {
    228         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
    229     }
    230     size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
    231     size_t initialOffset = this->addDraw(RESTORE, &size);
    232     this->validate(initialOffset, size);
    233 }
    234 
    235 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
    236     SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
    237 
    238     // op + dx + dy
    239     size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
    240     size_t initialOffset = this->addDraw(TRANSLATE, &size);
    241     this->addScalar(m.getTranslateX());
    242     this->addScalar(m.getTranslateY());
    243     this->validate(initialOffset, size);
    244 }
    245 
    246 void SkPictureRecord::recordScale(const SkMatrix& m) {
    247     SkASSERT(SkMatrix::kScale_Mask == m.getType());
    248 
    249     // op + sx + sy
    250     size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
    251     size_t initialOffset = this->addDraw(SCALE, &size);
    252     this->addScalar(m.getScaleX());
    253     this->addScalar(m.getScaleY());
    254     this->validate(initialOffset, size);
    255 }
    256 
    257 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
    258     switch (matrix.getType()) {
    259         case SkMatrix::kTranslate_Mask:
    260             this->recordTranslate(matrix);
    261             break;
    262         case SkMatrix::kScale_Mask:
    263             this->recordScale(matrix);
    264             break;
    265         default:
    266             this->recordConcat(matrix);
    267             break;
    268     }
    269     this->INHERITED::didConcat(matrix);
    270 }
    271 
    272 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
    273     this->validate(fWriter.bytesWritten(), 0);
    274     // op + matrix
    275     size_t size = kUInt32Size + matrix.writeToMemory(NULL);
    276     size_t initialOffset = this->addDraw(CONCAT, &size);
    277     this->addMatrix(matrix);
    278     this->validate(initialOffset, size);
    279 }
    280 
    281 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
    282     this->validate(fWriter.bytesWritten(), 0);
    283     // op + matrix
    284     size_t size = kUInt32Size + matrix.writeToMemory(NULL);
    285     size_t initialOffset = this->addDraw(SET_MATRIX, &size);
    286     this->addMatrix(matrix);
    287     this->validate(initialOffset, size);
    288     this->INHERITED::didSetMatrix(matrix);
    289 }
    290 
    291 static bool regionOpExpands(SkRegion::Op op) {
    292     switch (op) {
    293         case SkRegion::kUnion_Op:
    294         case SkRegion::kXOR_Op:
    295         case SkRegion::kReverseDifference_Op:
    296         case SkRegion::kReplace_Op:
    297             return true;
    298         case SkRegion::kIntersect_Op:
    299         case SkRegion::kDifference_Op:
    300             return false;
    301         default:
    302             SkDEBUGFAIL("unknown region op");
    303             return false;
    304     }
    305 }
    306 
    307 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
    308     int32_t offset = fRestoreOffsetStack.top();
    309     while (offset > 0) {
    310         uint32_t peek = fWriter.readTAt<uint32_t>(offset);
    311         fWriter.overwriteTAt(offset, restoreOffset);
    312         offset = peek;
    313     }
    314 
    315 #ifdef SK_DEBUG
    316     // offset of 0 has been disabled, so we skip it
    317     if (offset > 0) {
    318         // assert that the final offset value points to a save verb
    319         uint32_t opSize;
    320         DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
    321         SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp);
    322     }
    323 #endif
    324 }
    325 
    326 void SkPictureRecord::beginRecording() {
    327     // we have to call this *after* our constructor, to ensure that it gets
    328     // recorded. This is balanced by restoreToCount() call from endRecording,
    329     // which in-turn calls our overridden restore(), so those get recorded too.
    330     fInitialSaveCount = this->save();
    331 }
    332 
    333 void SkPictureRecord::endRecording() {
    334     SkASSERT(kNoInitialSave != fInitialSaveCount);
    335     this->restoreToCount(fInitialSaveCount);
    336 }
    337 
    338 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) {
    339     if (fRestoreOffsetStack.isEmpty()) {
    340         return -1;
    341     }
    342 
    343     // The RestoreOffset field is initially filled with a placeholder
    344     // value that points to the offset of the previous RestoreOffset
    345     // in the current stack level, thus forming a linked list so that
    346     // the restore offsets can be filled in when the corresponding
    347     // restore command is recorded.
    348     int32_t prevOffset = fRestoreOffsetStack.top();
    349 
    350     if (regionOpExpands(op)) {
    351         // Run back through any previous clip ops, and mark their offset to
    352         // be 0, disabling their ability to trigger a jump-to-restore, otherwise
    353         // they could hide this clips ability to expand the clip (i.e. go from
    354         // empty to non-empty).
    355         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
    356 
    357         // Reset the pointer back to the previous clip so that subsequent
    358         // restores don't overwrite the offsets we just cleared.
    359         prevOffset = 0;
    360     }
    361 
    362     size_t offset = fWriter.bytesWritten();
    363     this->addInt(prevOffset);
    364     fRestoreOffsetStack.top() = SkToU32(offset);
    365     return offset;
    366 }
    367 
    368 void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    369     this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
    370     this->INHERITED::onClipRect(rect, op, edgeStyle);
    371 }
    372 
    373 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
    374     // id + rect + clip params
    375     size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
    376     // recordRestoreOffsetPlaceholder doesn't always write an offset
    377     if (!fRestoreOffsetStack.isEmpty()) {
    378         // + restore offset
    379         size += kUInt32Size;
    380     }
    381     size_t initialOffset = this->addDraw(CLIP_RECT, &size);
    382     this->addRect(rect);
    383     this->addInt(ClipParams_pack(op, doAA));
    384     size_t offset = this->recordRestoreOffsetPlaceholder(op);
    385 
    386     this->validate(initialOffset, size);
    387     return offset;
    388 }
    389 
    390 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    391     this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
    392     this->INHERITED::onClipRRect(rrect, op, edgeStyle);
    393 }
    394 
    395 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
    396     // op + rrect + clip params
    397     size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
    398     // recordRestoreOffsetPlaceholder doesn't always write an offset
    399     if (!fRestoreOffsetStack.isEmpty()) {
    400         // + restore offset
    401         size += kUInt32Size;
    402     }
    403     size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
    404     this->addRRect(rrect);
    405     this->addInt(ClipParams_pack(op, doAA));
    406     size_t offset = recordRestoreOffsetPlaceholder(op);
    407     this->validate(initialOffset, size);
    408     return offset;
    409 }
    410 
    411 void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
    412     int pathID = this->addPathToHeap(path);
    413     this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
    414     this->INHERITED::onClipPath(path, op, edgeStyle);
    415 }
    416 
    417 size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) {
    418     // op + path index + clip params
    419     size_t size = 3 * kUInt32Size;
    420     // recordRestoreOffsetPlaceholder doesn't always write an offset
    421     if (!fRestoreOffsetStack.isEmpty()) {
    422         // + restore offset
    423         size += kUInt32Size;
    424     }
    425     size_t initialOffset = this->addDraw(CLIP_PATH, &size);
    426     this->addInt(pathID);
    427     this->addInt(ClipParams_pack(op, doAA));
    428     size_t offset = recordRestoreOffsetPlaceholder(op);
    429     this->validate(initialOffset, size);
    430     return offset;
    431 }
    432 
    433 void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) {
    434     this->recordClipRegion(region, op);
    435     this->INHERITED::onClipRegion(region, op);
    436 }
    437 
    438 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) {
    439     // op + clip params + region
    440     size_t size = 2 * kUInt32Size + region.writeToMemory(NULL);
    441     // recordRestoreOffsetPlaceholder doesn't always write an offset
    442     if (!fRestoreOffsetStack.isEmpty()) {
    443         // + restore offset
    444         size += kUInt32Size;
    445     }
    446     size_t initialOffset = this->addDraw(CLIP_REGION, &size);
    447     this->addRegion(region);
    448     this->addInt(ClipParams_pack(op, false));
    449     size_t offset = this->recordRestoreOffsetPlaceholder(op);
    450 
    451     this->validate(initialOffset, size);
    452     return offset;
    453 }
    454 
    455 void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
    456     // op + paint index
    457     size_t size = 2 * kUInt32Size;
    458     size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
    459     SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten());
    460     this->addPaint(paint);
    461     this->validate(initialOffset, size);
    462 }
    463 
    464 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
    465                                    const SkPaint& paint) {
    466     fContentInfo.onDrawPoints(count, paint);
    467 
    468     // op + paint index + mode + count + point data
    469     size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
    470     size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
    471     SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten());
    472     this->addPaint(paint);
    473 
    474     this->addInt(mode);
    475     this->addInt(SkToInt(count));
    476     fWriter.writeMul4(pts, count * sizeof(SkPoint));
    477     this->validate(initialOffset, size);
    478 }
    479 
    480 void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
    481     // op + paint index + rect
    482     size_t size = 2 * kUInt32Size + sizeof(oval);
    483     size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
    484     SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten());
    485     this->addPaint(paint);
    486     this->addRect(oval);
    487     this->validate(initialOffset, size);
    488 }
    489 
    490 void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
    491     // op + paint index + rect
    492     size_t size = 2 * kUInt32Size + sizeof(rect);
    493     size_t initialOffset = this->addDraw(DRAW_RECT, &size);
    494     SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten());
    495     this->addPaint(paint);
    496     this->addRect(rect);
    497     this->validate(initialOffset, size);
    498 }
    499 
    500 void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
    501     // op + paint index + rrect
    502     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
    503     size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
    504     SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten());
    505     this->addPaint(paint);
    506     this->addRRect(rrect);
    507     this->validate(initialOffset, size);
    508 }
    509 
    510 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
    511                                    const SkPaint& paint) {
    512     // op + paint index + rrects
    513     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
    514     size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
    515     SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten());
    516     this->addPaint(paint);
    517     this->addRRect(outer);
    518     this->addRRect(inner);
    519     this->validate(initialOffset, size);
    520 }
    521 
    522 void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
    523     fContentInfo.onDrawPath(path, paint);
    524 
    525     // op + paint index + path index
    526     size_t size = 3 * kUInt32Size;
    527     size_t initialOffset = this->addDraw(DRAW_PATH, &size);
    528     SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten());
    529     this->addPaint(paint);
    530     this->addPath(path);
    531     this->validate(initialOffset, size);
    532 }
    533 
    534 void SkPictureRecord::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
    535                                    const SkPaint* paint) {
    536     // op + paint index + bitmap index + left + top
    537     size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
    538     size_t initialOffset = this->addDraw(DRAW_BITMAP, &size);
    539     SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten());
    540     this->addPaintPtr(paint);
    541     this->addBitmap(bitmap);
    542     this->addScalar(left);
    543     this->addScalar(top);
    544     this->validate(initialOffset, size);
    545 }
    546 
    547 void SkPictureRecord::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
    548                                        const SkPaint* paint, DrawBitmapRectFlags flags) {
    549     // id + paint index + bitmap index + bool for 'src' + flags
    550     size_t size = 5 * kUInt32Size;
    551     if (src) {
    552         size += sizeof(*src);   // + rect
    553     }
    554     size += sizeof(dst);        // + rect
    555 
    556     size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size);
    557     SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT_TO_RECT, size)
    558              == fWriter.bytesWritten());
    559     this->addPaintPtr(paint);
    560     this->addBitmap(bitmap);
    561     this->addRectPtr(src);  // may be null
    562     this->addRect(dst);
    563     this->addInt(flags);
    564     this->validate(initialOffset, size);
    565 }
    566 
    567 void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
    568                                   const SkPaint* paint) {
    569     SkBitmap bm;
    570     if (as_IB(image)->getROPixels(&bm)) {
    571         this->SkPictureRecord::onDrawBitmap(bm, x, y, paint);
    572     }
    573 }
    574 
    575 void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
    576                                       const SkPaint* paint) {
    577     SkBitmap bm;
    578     if (as_IB(image)->getROPixels(&bm)) {
    579         this->SkPictureRecord::onDrawBitmapRect(bm, src, dst, paint, kNone_DrawBitmapRectFlag);
    580     }
    581 }
    582 
    583 void SkPictureRecord::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
    584                                        const SkRect& dst, const SkPaint* paint) {
    585     // op + paint index + bitmap id + center + dst rect
    586     size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst);
    587     size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size);
    588     SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten());
    589     this->addPaintPtr(paint);
    590     this->addBitmap(bitmap);
    591     this->addIRect(center);
    592     this->addRect(dst);
    593     this->validate(initialOffset, size);
    594 }
    595 
    596 void SkPictureRecord::onDrawSprite(const SkBitmap& bitmap, int left, int top,
    597                                    const SkPaint* paint) {
    598     // op + paint index + bitmap index + left + top
    599     size_t size = 5 * kUInt32Size;
    600     size_t initialOffset = this->addDraw(DRAW_SPRITE, &size);
    601     SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten());
    602     this->addPaintPtr(paint);
    603     this->addBitmap(bitmap);
    604     this->addInt(left);
    605     this->addInt(top);
    606     this->validate(initialOffset, size);
    607 }
    608 
    609 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
    610                                  const SkPaint& paint) {
    611     // op + paint index + length + 'length' worth of chars + x + y
    612     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
    613 
    614     DrawType op = DRAW_TEXT;
    615     size_t initialOffset = this->addDraw(op, &size);
    616     SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
    617     this->addPaint(paint);
    618     this->addText(text, byteLength);
    619     this->addScalar(x);
    620     this->addScalar(y);
    621     this->validate(initialOffset, size);
    622 }
    623 
    624 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
    625                                     const SkPaint& paint) {
    626     int points = paint.countText(text, byteLength);
    627 
    628     // op + paint index + length + 'length' worth of data + num points + x&y point data
    629     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
    630 
    631     DrawType op = DRAW_POS_TEXT;
    632 
    633     size_t initialOffset = this->addDraw(op, &size);
    634     SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten());
    635     this->addPaint(paint);
    636     this->addText(text, byteLength);
    637     this->addInt(points);
    638     fWriter.writeMul4(pos, points * sizeof(SkPoint));
    639     this->validate(initialOffset, size);
    640 }
    641 
    642 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
    643                                      SkScalar constY, const SkPaint& paint) {
    644     int points = paint.countText(text, byteLength);
    645 
    646     // op + paint index + length + 'length' worth of data + num points
    647     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
    648     // + y + the actual points
    649     size += 1 * kUInt32Size + points * sizeof(SkScalar);
    650 
    651     size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
    652     this->addPaint(paint);
    653     this->addText(text, byteLength);
    654     this->addInt(points);
    655     this->addScalar(constY);
    656     fWriter.writeMul4(xpos, points * sizeof(SkScalar));
    657     this->validate(initialOffset, size);
    658 }
    659 
    660 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
    661                                        const SkMatrix* matrix, const SkPaint& paint) {
    662     // op + paint index + length + 'length' worth of data + path index + matrix
    663     const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
    664     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL);
    665     size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
    666     SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten());
    667     this->addPaint(paint);
    668     this->addText(text, byteLength);
    669     this->addPath(path);
    670     this->addMatrix(m);
    671     this->validate(initialOffset, size);
    672 }
    673 
    674 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
    675                                      const SkPaint& paint) {
    676 
    677     // op + paint index + blob index + x/y
    678     size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
    679     size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
    680     SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten());
    681 
    682     this->addPaint(paint);
    683     this->addTextBlob(blob);
    684     this->addScalar(x);
    685     this->addScalar(y);
    686 
    687     this->validate(initialOffset, size);
    688 }
    689 
    690 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
    691                                     const SkPaint* paint) {
    692     // op + picture index
    693     size_t size = 2 * kUInt32Size;
    694     size_t initialOffset;
    695 
    696     if (NULL == matrix && NULL == paint) {
    697         initialOffset = this->addDraw(DRAW_PICTURE, &size);
    698         this->addPicture(picture);
    699     } else {
    700         const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
    701         size += m.writeToMemory(NULL) + kUInt32Size;    // matrix + paint
    702         initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
    703         SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size)
    704                  == fWriter.bytesWritten());
    705         this->addPaintPtr(paint);
    706         this->addMatrix(m);
    707         this->addPicture(picture);
    708     }
    709     this->validate(initialOffset, size);
    710 }
    711 
    712 void SkPictureRecord::onDrawVertices(VertexMode vmode, int vertexCount,
    713                                      const SkPoint vertices[], const SkPoint texs[],
    714                                      const SkColor colors[], SkXfermode* xfer,
    715                                      const uint16_t indices[], int indexCount,
    716                                      const SkPaint& paint) {
    717     uint32_t flags = 0;
    718     if (texs) {
    719         flags |= DRAW_VERTICES_HAS_TEXS;
    720     }
    721     if (colors) {
    722         flags |= DRAW_VERTICES_HAS_COLORS;
    723     }
    724     if (indexCount > 0) {
    725         flags |= DRAW_VERTICES_HAS_INDICES;
    726     }
    727     if (xfer) {
    728         SkXfermode::Mode mode;
    729         if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
    730             flags |= DRAW_VERTICES_HAS_XFER;
    731         }
    732     }
    733 
    734     // op + paint index + flags + vmode + vCount + vertices
    735     size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint);
    736     if (flags & DRAW_VERTICES_HAS_TEXS) {
    737         size += vertexCount * sizeof(SkPoint);  // + uvs
    738     }
    739     if (flags & DRAW_VERTICES_HAS_COLORS) {
    740         size += vertexCount * sizeof(SkColor);  // + vert colors
    741     }
    742     if (flags & DRAW_VERTICES_HAS_INDICES) {
    743         // + num indices + indices
    744         size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t));
    745     }
    746     if (flags & DRAW_VERTICES_HAS_XFER) {
    747         size += kUInt32Size;    // mode enum
    748     }
    749 
    750     size_t initialOffset = this->addDraw(DRAW_VERTICES, &size);
    751     SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten());
    752     this->addPaint(paint);
    753     this->addInt(flags);
    754     this->addInt(vmode);
    755     this->addInt(vertexCount);
    756     this->addPoints(vertices, vertexCount);
    757     if (flags & DRAW_VERTICES_HAS_TEXS) {
    758         this->addPoints(texs, vertexCount);
    759     }
    760     if (flags & DRAW_VERTICES_HAS_COLORS) {
    761         fWriter.writeMul4(colors, vertexCount * sizeof(SkColor));
    762     }
    763     if (flags & DRAW_VERTICES_HAS_INDICES) {
    764         this->addInt(indexCount);
    765         fWriter.writePad(indices, indexCount * sizeof(uint16_t));
    766     }
    767     if (flags & DRAW_VERTICES_HAS_XFER) {
    768         SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
    769         (void)xfer->asMode(&mode);
    770         this->addInt(mode);
    771     }
    772     this->validate(initialOffset, size);
    773 }
    774 
    775 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
    776                                   const SkPoint texCoords[4], SkXfermode* xmode,
    777                                   const SkPaint& paint) {
    778     // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
    779     size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
    780     uint32_t flag = 0;
    781     if (colors) {
    782         flag |= DRAW_VERTICES_HAS_COLORS;
    783         size += SkPatchUtils::kNumCorners * sizeof(SkColor);
    784     }
    785     if (texCoords) {
    786         flag |= DRAW_VERTICES_HAS_TEXS;
    787         size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
    788     }
    789     if (xmode) {
    790         SkXfermode::Mode mode;
    791         if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) {
    792             flag |= DRAW_VERTICES_HAS_XFER;
    793             size += kUInt32Size;
    794         }
    795     }
    796 
    797     size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
    798     SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten());
    799     this->addPaint(paint);
    800     this->addPatch(cubics);
    801     this->addInt(flag);
    802 
    803     // write optional parameters
    804     if (colors) {
    805         fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
    806     }
    807     if (texCoords) {
    808         fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
    809     }
    810     if (flag & DRAW_VERTICES_HAS_XFER) {
    811         SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
    812         xmode->asMode(&mode);
    813         this->addInt(mode);
    814     }
    815     this->validate(initialOffset, size);
    816 }
    817 
    818 void SkPictureRecord::beginCommentGroup(const char* description) {
    819     // op/size + length of string + \0 terminated chars
    820     size_t length = strlen(description);
    821     size_t size = 2 * kUInt32Size + SkAlign4(length + 1);
    822     size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size);
    823     fWriter.writeString(description, length);
    824     this->validate(initialOffset, size);
    825 }
    826 
    827 void SkPictureRecord::addComment(const char* kywd, const char* value) {
    828     // op/size + 2x length of string + 2x \0 terminated chars
    829     size_t kywdLen = strlen(kywd);
    830     size_t valueLen = strlen(value);
    831     size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1);
    832     size_t initialOffset = this->addDraw(COMMENT, &size);
    833     fWriter.writeString(kywd, kywdLen);
    834     fWriter.writeString(value, valueLen);
    835     this->validate(initialOffset, size);
    836 }
    837 
    838 void SkPictureRecord::endCommentGroup() {
    839     // op/size
    840     size_t size = 1 * kUInt32Size;
    841     size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size);
    842     this->validate(initialOffset, size);
    843 }
    844 
    845 ///////////////////////////////////////////////////////////////////////////////
    846 
    847 SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
    848     return NULL;
    849 }
    850 
    851 // If we already have a stored, can we reuse it instead of also storing b?
    852 static bool equivalent(const SkBitmap& a, const SkBitmap& b) {
    853     if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) {
    854         // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch),
    855         // but it sure makes things easier to reason about below.
    856         return false;
    857     }
    858     if (a.pixelRef() == b.pixelRef()) {
    859         return true;  // Same shape and same pixels -> same bitmap.
    860     }
    861 
    862     // From here down we're going to have to look at the bitmap data, so we require pixelRefs().
    863     if (!a.pixelRef() || !b.pixelRef()) {
    864         return false;
    865     }
    866 
    867     // If the bitmaps have encoded data, check first before locking pixels so they don't decode.
    868     SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()),
    869                          encB(b.pixelRef()->refEncodedData());
    870     if (encA && encB) {
    871         return encA->equals(encB);
    872     } else if (encA || encB) {
    873         return false;   // One has encoded data but the other does not.
    874     }
    875 
    876     // As a last resort, we have to look at the pixels.  This will read back textures.
    877     SkAutoLockPixels al(a), bl(b);
    878     const char* ap = (const char*)a.getPixels();
    879     const char* bp = (const char*)b.getPixels();
    880     if (ap && bp) {
    881         // We check row by row; row bytes might differ.
    882         SkASSERT(a.info() == b.info());          // We checked this above.
    883         SkASSERT(a.info().bytesPerPixel() > 0);  // If we have pixelRefs, this better be true.
    884         const SkImageInfo info = a.info();
    885         const size_t bytesToCompare = info.width() * info.bytesPerPixel();
    886         for (int row = 0; row < info.height(); row++) {
    887             if (0 != memcmp(ap, bp, bytesToCompare)) {
    888                 return false;
    889             }
    890             ap += a.rowBytes();
    891             bp += b.rowBytes();
    892         }
    893         return true;
    894     }
    895     return false;  // Couldn't get pixels for both bitmaps.
    896 }
    897 
    898 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) {
    899     // First see if we already have this bitmap.  This deduplication should really
    900     // only be important for our tests, where bitmaps tend not to be tagged immutable.
    901     // In Chrome (and hopefully Android?) they're typically immutable.
    902     for (int i = 0; i < fBitmaps.count(); i++) {
    903         if (equivalent(fBitmaps[i], bitmap)) {
    904             this->addInt(i);  // Unlike the rest, bitmap indices are 0-based.
    905             return;
    906         }
    907     }
    908     // Don't have it.  We'll add it to our list, making sure it's tagged as immutable.
    909     if (bitmap.isImmutable()) {
    910         // Shallow copies of bitmaps are cheap, so immutable == fast.
    911         fBitmaps.push_back(bitmap);
    912     } else {
    913         // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage.
    914         SkBitmap copy;
    915         bitmap.copyTo(&copy);
    916         copy.setImmutable();
    917         fBitmaps.push_back(copy);
    918     }
    919     this->addInt(fBitmaps.count()-1);  // Remember, 0-based.
    920 }
    921 
    922 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
    923     fWriter.writeMatrix(matrix);
    924 }
    925 
    926 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
    927     fContentInfo.onAddPaintPtr(paint);
    928 
    929     if (paint) {
    930         fPaints.push_back(*paint);
    931         this->addInt(fPaints.count());
    932     } else {
    933         this->addInt(0);
    934     }
    935 }
    936 
    937 int SkPictureRecord::addPathToHeap(const SkPath& path) {
    938     fPaths.push_back(path);
    939     return fPaths.count();
    940 }
    941 
    942 void SkPictureRecord::addPath(const SkPath& path) {
    943     this->addInt(this->addPathToHeap(path));
    944 }
    945 
    946 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
    947     fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
    948 }
    949 
    950 void SkPictureRecord::addPicture(const SkPicture* picture) {
    951     int index = fPictureRefs.find(picture);
    952     if (index < 0) {    // not found
    953         index = fPictureRefs.count();
    954         *fPictureRefs.append() = picture;
    955         picture->ref();
    956     }
    957     // follow the convention of recording a 1-based index
    958     this->addInt(index + 1);
    959 }
    960 
    961 void SkPictureRecord::addPoint(const SkPoint& point) {
    962     fWriter.writePoint(point);
    963 }
    964 
    965 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
    966     fWriter.writeMul4(pts, count * sizeof(SkPoint));
    967 }
    968 
    969 void SkPictureRecord::addNoOp() {
    970     size_t size = kUInt32Size; // op
    971     this->addDraw(NOOP, &size);
    972 }
    973 
    974 void SkPictureRecord::addRect(const SkRect& rect) {
    975     fWriter.writeRect(rect);
    976 }
    977 
    978 void SkPictureRecord::addRectPtr(const SkRect* rect) {
    979     if (fWriter.writeBool(rect != NULL)) {
    980         fWriter.writeRect(*rect);
    981     }
    982 }
    983 
    984 void SkPictureRecord::addIRect(const SkIRect& rect) {
    985     fWriter.write(&rect, sizeof(rect));
    986 }
    987 
    988 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
    989     if (fWriter.writeBool(rect != NULL)) {
    990         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
    991     }
    992 }
    993 
    994 void SkPictureRecord::addRRect(const SkRRect& rrect) {
    995     fWriter.writeRRect(rrect);
    996 }
    997 
    998 void SkPictureRecord::addRegion(const SkRegion& region) {
    999     fWriter.writeRegion(region);
   1000 }
   1001 
   1002 void SkPictureRecord::addText(const void* text, size_t byteLength) {
   1003     fContentInfo.onDrawText();
   1004     addInt(SkToInt(byteLength));
   1005     fWriter.writePad(text, byteLength);
   1006 }
   1007 
   1008 void SkPictureRecord::addTextBlob(const SkTextBlob *blob) {
   1009     int index = fTextBlobRefs.count();
   1010     *fTextBlobRefs.append() = blob;
   1011     blob->ref();
   1012     // follow the convention of recording a 1-based index
   1013     this->addInt(index + 1);
   1014 }
   1015 
   1016 ///////////////////////////////////////////////////////////////////////////////
   1017 
   1018