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 "SkImage_Base.h"
     10 #include "SkPatchUtils.h"
     11 #include "SkPixelRef.h"
     12 #include "SkRRect.h"
     13 #include "SkRSXform.h"
     14 #include "SkTextBlob.h"
     15 #include "SkTSearch.h"
     16 #include "SkClipOpPriv.h"
     17 
     18 #define HEAP_BLOCK_SIZE 4096
     19 
     20 enum {
     21     // just need a value that save or getSaveCount would never return
     22     kNoInitialSave = -1,
     23 };
     24 
     25 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc.
     26 static int const kUInt32Size = 4;
     27 
     28 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags)
     29     : INHERITED(dimensions.width(), dimensions.height())
     30     , fRecordFlags(flags)
     31     , fInitialSaveCount(kNoInitialSave) {
     32 }
     33 
     34 SkPictureRecord::~SkPictureRecord() {
     35     fImageRefs.unrefAll();
     36     fPictureRefs.unrefAll();
     37     fDrawableRefs.unrefAll();
     38     fTextBlobRefs.unrefAll();
     39     fVerticesRefs.unrefAll();
     40 }
     41 
     42 ///////////////////////////////////////////////////////////////////////////////
     43 
     44 void SkPictureRecord::willSave() {
     45     // record the offset to us, making it non-positive to distinguish a save
     46     // from a clip entry.
     47     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
     48     this->recordSave();
     49 
     50     this->INHERITED::willSave();
     51 }
     52 
     53 void SkPictureRecord::recordSave() {
     54     fContentInfo.onSave();
     55 
     56     // op only
     57     size_t size = sizeof(kUInt32Size);
     58     size_t initialOffset = this->addDraw(SAVE, &size);
     59 
     60     this->validate(initialOffset, size);
     61 }
     62 
     63 SkCanvas::SaveLayerStrategy SkPictureRecord::getSaveLayerStrategy(const SaveLayerRec& rec) {
     64     // record the offset to us, making it non-positive to distinguish a save
     65     // from a clip entry.
     66     fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten());
     67     this->recordSaveLayer(rec);
     68 
     69     (void)this->INHERITED::getSaveLayerStrategy(rec);
     70     /*  No need for a (potentially very big) layer which we don't actually need
     71         at this time (and may not be able to afford since during record our
     72         clip starts out the size of the picture, which is often much larger
     73         than the size of the actual device we'll use during playback).
     74      */
     75     return kNoLayer_SaveLayerStrategy;
     76 }
     77 
     78 void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) {
     79     fContentInfo.onSaveLayer();
     80 
     81     // op + flatflags
     82     size_t size = 2 * kUInt32Size;
     83     uint32_t flatFlags = 0;
     84 
     85     if (rec.fBounds) {
     86         flatFlags |= SAVELAYERREC_HAS_BOUNDS;
     87         size += sizeof(*rec.fBounds);
     88     }
     89     if (rec.fPaint) {
     90         flatFlags |= SAVELAYERREC_HAS_PAINT;
     91         size += sizeof(uint32_t); // index
     92     }
     93     if (rec.fBackdrop) {
     94         flatFlags |= SAVELAYERREC_HAS_BACKDROP;
     95         size += sizeof(uint32_t); // (paint) index
     96     }
     97     if (rec.fSaveLayerFlags) {
     98         flatFlags |= SAVELAYERREC_HAS_FLAGS;
     99         size += sizeof(uint32_t);
    100     }
    101 
    102     const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size);
    103     this->addInt(flatFlags);
    104     if (flatFlags & SAVELAYERREC_HAS_BOUNDS) {
    105         this->addRect(*rec.fBounds);
    106     }
    107     if (flatFlags & SAVELAYERREC_HAS_PAINT) {
    108         this->addPaintPtr(rec.fPaint);
    109     }
    110     if (flatFlags & SAVELAYERREC_HAS_BACKDROP) {
    111         // overkill, but we didn't already track single flattenables, so using a paint for that
    112         SkPaint paint;
    113         paint.setImageFilter(sk_ref_sp(const_cast<SkImageFilter*>(rec.fBackdrop)));
    114         this->addPaint(paint);
    115     }
    116     if (flatFlags & SAVELAYERREC_HAS_FLAGS) {
    117         this->addInt(rec.fSaveLayerFlags);
    118     }
    119     this->validate(initialOffset, size);
    120 }
    121 
    122 #ifdef SK_DEBUG
    123 /*
    124  * Read the op code from 'offset' in 'writer' and extract the size too.
    125  */
    126 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) {
    127     uint32_t peek = writer->readTAt<uint32_t>(offset);
    128 
    129     uint32_t op;
    130     UNPACK_8_24(peek, op, *size);
    131     if (MASK_24 == *size) {
    132         // size required its own slot right after the op code
    133         *size = writer->readTAt<uint32_t>(offset + kUInt32Size);
    134     }
    135     return (DrawType) op;
    136 }
    137 #endif//SK_DEBUG
    138 
    139 void SkPictureRecord::willRestore() {
    140 #if 0
    141     SkASSERT(fRestoreOffsetStack.count() > 1);
    142 #endif
    143 
    144     // check for underflow
    145     if (fRestoreOffsetStack.count() == 0) {
    146         return;
    147     }
    148 
    149     this->recordRestore();
    150 
    151     fRestoreOffsetStack.pop();
    152 
    153     this->INHERITED::willRestore();
    154 }
    155 
    156 void SkPictureRecord::recordRestore(bool fillInSkips) {
    157     fContentInfo.onRestore();
    158 
    159     if (fillInSkips) {
    160         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten());
    161     }
    162     size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code
    163     size_t initialOffset = this->addDraw(RESTORE, &size);
    164     this->validate(initialOffset, size);
    165 }
    166 
    167 void SkPictureRecord::recordTranslate(const SkMatrix& m) {
    168     SkASSERT(SkMatrix::kTranslate_Mask == m.getType());
    169 
    170     // op + dx + dy
    171     size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
    172     size_t initialOffset = this->addDraw(TRANSLATE, &size);
    173     this->addScalar(m.getTranslateX());
    174     this->addScalar(m.getTranslateY());
    175     this->validate(initialOffset, size);
    176 }
    177 
    178 void SkPictureRecord::recordScale(const SkMatrix& m) {
    179     SkASSERT(SkMatrix::kScale_Mask == m.getType());
    180 
    181     // op + sx + sy
    182     size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
    183     size_t initialOffset = this->addDraw(SCALE, &size);
    184     this->addScalar(m.getScaleX());
    185     this->addScalar(m.getScaleY());
    186     this->validate(initialOffset, size);
    187 }
    188 
    189 void SkPictureRecord::didConcat(const SkMatrix& matrix) {
    190     switch (matrix.getType()) {
    191         case SkMatrix::kTranslate_Mask:
    192             this->recordTranslate(matrix);
    193             break;
    194         case SkMatrix::kScale_Mask:
    195             this->recordScale(matrix);
    196             break;
    197         default:
    198             this->recordConcat(matrix);
    199             break;
    200     }
    201     this->INHERITED::didConcat(matrix);
    202 }
    203 
    204 void SkPictureRecord::recordConcat(const SkMatrix& matrix) {
    205     this->validate(fWriter.bytesWritten(), 0);
    206     // op + matrix
    207     size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
    208     size_t initialOffset = this->addDraw(CONCAT, &size);
    209     this->addMatrix(matrix);
    210     this->validate(initialOffset, size);
    211 }
    212 
    213 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) {
    214     this->validate(fWriter.bytesWritten(), 0);
    215     // op + matrix
    216     size_t size = kUInt32Size + matrix.writeToMemory(nullptr);
    217     size_t initialOffset = this->addDraw(SET_MATRIX, &size);
    218     this->addMatrix(matrix);
    219     this->validate(initialOffset, size);
    220     this->INHERITED::didSetMatrix(matrix);
    221 }
    222 
    223 void SkPictureRecord::didTranslateZ(SkScalar z) {
    224 #ifdef SK_EXPERIMENTAL_SHADOWING
    225     this->validate(fWriter.bytesWritten(), 0);
    226     // op + scalar
    227     size_t size = 1 * kUInt32Size + 1 * sizeof(SkScalar);
    228     size_t initialOffset = this->addDraw(TRANSLATE_Z, &size);
    229     this->addScalar(z);
    230     this->validate(initialOffset, size);
    231     this->INHERITED::didTranslateZ(z);
    232 #endif
    233 }
    234 
    235 static bool clipOpExpands(SkClipOp op) {
    236     switch (op) {
    237         case kUnion_SkClipOp:
    238         case kXOR_SkClipOp:
    239         case kReverseDifference_SkClipOp:
    240         case kReplace_SkClipOp:
    241             return true;
    242         case kIntersect_SkClipOp:
    243         case kDifference_SkClipOp:
    244             return false;
    245         default:
    246             SkDEBUGFAIL("unknown clipop");
    247             return false;
    248     }
    249 }
    250 
    251 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) {
    252     int32_t offset = fRestoreOffsetStack.top();
    253     while (offset > 0) {
    254         uint32_t peek = fWriter.readTAt<uint32_t>(offset);
    255         fWriter.overwriteTAt(offset, restoreOffset);
    256         offset = peek;
    257     }
    258 
    259 #ifdef SK_DEBUG
    260     // offset of 0 has been disabled, so we skip it
    261     if (offset > 0) {
    262         // assert that the final offset value points to a save verb
    263         uint32_t opSize;
    264         DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize);
    265         SkASSERT(SAVE_LAYER_SAVEFLAGS_DEPRECATED != drawOp);
    266         SkASSERT(SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016 != drawOp);
    267         SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERREC == drawOp);
    268     }
    269 #endif
    270 }
    271 
    272 void SkPictureRecord::beginRecording() {
    273     // we have to call this *after* our constructor, to ensure that it gets
    274     // recorded. This is balanced by restoreToCount() call from endRecording,
    275     // which in-turn calls our overridden restore(), so those get recorded too.
    276     fInitialSaveCount = this->save();
    277 }
    278 
    279 void SkPictureRecord::endRecording() {
    280     SkASSERT(kNoInitialSave != fInitialSaveCount);
    281     this->restoreToCount(fInitialSaveCount);
    282 }
    283 
    284 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkClipOp op) {
    285     if (fRestoreOffsetStack.isEmpty()) {
    286         return -1;
    287     }
    288 
    289     // The RestoreOffset field is initially filled with a placeholder
    290     // value that points to the offset of the previous RestoreOffset
    291     // in the current stack level, thus forming a linked list so that
    292     // the restore offsets can be filled in when the corresponding
    293     // restore command is recorded.
    294     int32_t prevOffset = fRestoreOffsetStack.top();
    295 
    296     if (clipOpExpands(op)) {
    297         // Run back through any previous clip ops, and mark their offset to
    298         // be 0, disabling their ability to trigger a jump-to-restore, otherwise
    299         // they could hide this clips ability to expand the clip (i.e. go from
    300         // empty to non-empty).
    301         this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0);
    302 
    303         // Reset the pointer back to the previous clip so that subsequent
    304         // restores don't overwrite the offsets we just cleared.
    305         prevOffset = 0;
    306     }
    307 
    308     size_t offset = fWriter.bytesWritten();
    309     this->addInt(prevOffset);
    310     fRestoreOffsetStack.top() = SkToU32(offset);
    311     return offset;
    312 }
    313 
    314 void SkPictureRecord::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
    315     this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle);
    316     this->INHERITED::onClipRect(rect, op, edgeStyle);
    317 }
    318 
    319 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkClipOp op, bool doAA) {
    320     // id + rect + clip params
    321     size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size;
    322     // recordRestoreOffsetPlaceholder doesn't always write an offset
    323     if (!fRestoreOffsetStack.isEmpty()) {
    324         // + restore offset
    325         size += kUInt32Size;
    326     }
    327     size_t initialOffset = this->addDraw(CLIP_RECT, &size);
    328     this->addRect(rect);
    329     this->addInt(ClipParams_pack(op, doAA));
    330     size_t offset = this->recordRestoreOffsetPlaceholder(op);
    331 
    332     this->validate(initialOffset, size);
    333     return offset;
    334 }
    335 
    336 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) {
    337     this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle);
    338     this->INHERITED::onClipRRect(rrect, op, edgeStyle);
    339 }
    340 
    341 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) {
    342     // op + rrect + clip params
    343     size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size;
    344     // recordRestoreOffsetPlaceholder doesn't always write an offset
    345     if (!fRestoreOffsetStack.isEmpty()) {
    346         // + restore offset
    347         size += kUInt32Size;
    348     }
    349     size_t initialOffset = this->addDraw(CLIP_RRECT, &size);
    350     this->addRRect(rrect);
    351     this->addInt(ClipParams_pack(op, doAA));
    352     size_t offset = recordRestoreOffsetPlaceholder(op);
    353     this->validate(initialOffset, size);
    354     return offset;
    355 }
    356 
    357 void SkPictureRecord::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) {
    358     int pathID = this->addPathToHeap(path);
    359     this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle);
    360     this->INHERITED::onClipPath(path, op, edgeStyle);
    361 }
    362 
    363 size_t SkPictureRecord::recordClipPath(int pathID, SkClipOp op, bool doAA) {
    364     // op + path index + clip params
    365     size_t size = 3 * kUInt32Size;
    366     // recordRestoreOffsetPlaceholder doesn't always write an offset
    367     if (!fRestoreOffsetStack.isEmpty()) {
    368         // + restore offset
    369         size += kUInt32Size;
    370     }
    371     size_t initialOffset = this->addDraw(CLIP_PATH, &size);
    372     this->addInt(pathID);
    373     this->addInt(ClipParams_pack(op, doAA));
    374     size_t offset = recordRestoreOffsetPlaceholder(op);
    375     this->validate(initialOffset, size);
    376     return offset;
    377 }
    378 
    379 void SkPictureRecord::onClipRegion(const SkRegion& region, SkClipOp op) {
    380     this->recordClipRegion(region, op);
    381     this->INHERITED::onClipRegion(region, op);
    382 }
    383 
    384 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkClipOp op) {
    385     // op + clip params + region
    386     size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr);
    387     // recordRestoreOffsetPlaceholder doesn't always write an offset
    388     if (!fRestoreOffsetStack.isEmpty()) {
    389         // + restore offset
    390         size += kUInt32Size;
    391     }
    392     size_t initialOffset = this->addDraw(CLIP_REGION, &size);
    393     this->addRegion(region);
    394     this->addInt(ClipParams_pack(op, false));
    395     size_t offset = this->recordRestoreOffsetPlaceholder(op);
    396 
    397     this->validate(initialOffset, size);
    398     return offset;
    399 }
    400 
    401 void SkPictureRecord::onDrawPaint(const SkPaint& paint) {
    402     // op + paint index
    403     size_t size = 2 * kUInt32Size;
    404     size_t initialOffset = this->addDraw(DRAW_PAINT, &size);
    405     this->addPaint(paint);
    406     this->validate(initialOffset, size);
    407 }
    408 
    409 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[],
    410                                    const SkPaint& paint) {
    411     fContentInfo.onDrawPoints(count, paint);
    412 
    413     // op + paint index + mode + count + point data
    414     size_t size = 4 * kUInt32Size + count * sizeof(SkPoint);
    415     size_t initialOffset = this->addDraw(DRAW_POINTS, &size);
    416     this->addPaint(paint);
    417 
    418     this->addInt(mode);
    419     this->addInt(SkToInt(count));
    420     fWriter.writeMul4(pts, count * sizeof(SkPoint));
    421     this->validate(initialOffset, size);
    422 }
    423 
    424 void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) {
    425     // op + paint index + rect
    426     size_t size = 2 * kUInt32Size + sizeof(oval);
    427     size_t initialOffset = this->addDraw(DRAW_OVAL, &size);
    428     this->addPaint(paint);
    429     this->addRect(oval);
    430     this->validate(initialOffset, size);
    431 }
    432 
    433 void SkPictureRecord::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
    434                                 bool useCenter, const SkPaint& paint) {
    435     // op + paint index + rect + start + sweep + bool (as int)
    436     size_t size = 2 * kUInt32Size + sizeof(oval) + sizeof(startAngle) + sizeof(sweepAngle) +
    437                   sizeof(int);
    438     size_t initialOffset = this->addDraw(DRAW_ARC, &size);
    439     this->addPaint(paint);
    440     this->addRect(oval);
    441     this->addScalar(startAngle);
    442     this->addScalar(sweepAngle);
    443     this->addInt(useCenter);
    444     this->validate(initialOffset, size);
    445 }
    446 
    447 void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) {
    448     // op + paint index + rect
    449     size_t size = 2 * kUInt32Size + sizeof(rect);
    450     size_t initialOffset = this->addDraw(DRAW_RECT, &size);
    451     this->addPaint(paint);
    452     this->addRect(rect);
    453     this->validate(initialOffset, size);
    454 }
    455 
    456 void SkPictureRecord::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
    457     // op + paint index + region
    458     size_t regionBytes = region.writeToMemory(nullptr);
    459     size_t size = 2 * kUInt32Size + regionBytes;
    460     size_t initialOffset = this->addDraw(DRAW_REGION, &size);
    461     this->addPaint(paint);
    462     fWriter.writeRegion(region);
    463     this->validate(initialOffset, size);
    464 }
    465 
    466 void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
    467     // op + paint index + rrect
    468     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory;
    469     size_t initialOffset = this->addDraw(DRAW_RRECT, &size);
    470     this->addPaint(paint);
    471     this->addRRect(rrect);
    472     this->validate(initialOffset, size);
    473 }
    474 
    475 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
    476                                    const SkPaint& paint) {
    477     // op + paint index + rrects
    478     size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2;
    479     size_t initialOffset = this->addDraw(DRAW_DRRECT, &size);
    480     this->addPaint(paint);
    481     this->addRRect(outer);
    482     this->addRRect(inner);
    483     this->validate(initialOffset, size);
    484 }
    485 
    486 void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
    487     fContentInfo.onDrawPath(path, paint);
    488 
    489     // op + paint index + path index
    490     size_t size = 3 * kUInt32Size;
    491     size_t initialOffset = this->addDraw(DRAW_PATH, &size);
    492     this->addPaint(paint);
    493     this->addPath(path);
    494     this->validate(initialOffset, size);
    495 }
    496 
    497 void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y,
    498                                   const SkPaint* paint) {
    499     // op + paint_index + image_index + x + y
    500     size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
    501     size_t initialOffset = this->addDraw(DRAW_IMAGE, &size);
    502     this->addPaintPtr(paint);
    503     this->addImage(image);
    504     this->addScalar(x);
    505     this->addScalar(y);
    506     this->validate(initialOffset, size);
    507 }
    508 
    509 void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
    510                                       const SkPaint* paint, SrcRectConstraint constraint) {
    511     // id + paint_index + image_index + bool_for_src + constraint
    512     size_t size = 5 * kUInt32Size;
    513     if (src) {
    514         size += sizeof(*src);   // + rect
    515     }
    516     size += sizeof(dst);        // + rect
    517 
    518     size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size);
    519     this->addPaintPtr(paint);
    520     this->addImage(image);
    521     this->addRectPtr(src);  // may be null
    522     this->addRect(dst);
    523     this->addInt(constraint);
    524     this->validate(initialOffset, size);
    525 }
    526 
    527 void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
    528                                       const SkPaint* paint) {
    529     // id + paint_index + image_index + center + dst
    530     size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect);
    531 
    532     size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size);
    533     this->addPaintPtr(paint);
    534     this->addImage(img);
    535     this->addIRect(center);
    536     this->addRect(dst);
    537     this->validate(initialOffset, size);
    538 }
    539 
    540 void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
    541                                          const SkRect& dst, const SkPaint* paint) {
    542     // xCount + xDivs + yCount+ yDivs
    543     int flagCount = (nullptr == lattice.fFlags) ? 0 : (lattice.fXCount + 1) * (lattice.fYCount + 1);
    544     size_t latticeSize = (1 + lattice.fXCount + 1 + lattice.fYCount + 1) * kUInt32Size +
    545                          SkAlign4(flagCount * sizeof(SkCanvas::Lattice::Flags)) + sizeof(SkIRect);
    546 
    547     // op + paint index + image index + lattice + dst rect
    548     size_t size = 3 * kUInt32Size + latticeSize + sizeof(dst);
    549     size_t initialOffset = this->addDraw(DRAW_IMAGE_LATTICE, &size);
    550     this->addPaintPtr(paint);
    551     this->addImage(image);
    552     this->addInt(lattice.fXCount);
    553     fWriter.writePad(lattice.fXDivs, lattice.fXCount * kUInt32Size);
    554     this->addInt(lattice.fYCount);
    555     fWriter.writePad(lattice.fYDivs, lattice.fYCount * kUInt32Size);
    556     this->addInt(flagCount);
    557     fWriter.writePad(lattice.fFlags, flagCount * sizeof(SkCanvas::Lattice::Flags));
    558     SkASSERT(lattice.fBounds);
    559     this->addIRect(*lattice.fBounds);
    560     this->addRect(dst);
    561     this->validate(initialOffset, size);
    562 }
    563 
    564 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
    565                                  const SkPaint& paint) {
    566     // op + paint index + length + 'length' worth of chars + x + y
    567     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar);
    568 
    569     DrawType op = DRAW_TEXT;
    570     size_t initialOffset = this->addDraw(op, &size);
    571     this->addPaint(paint);
    572     this->addText(text, byteLength);
    573     this->addScalar(x);
    574     this->addScalar(y);
    575     this->validate(initialOffset, size);
    576 }
    577 
    578 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
    579                                     const SkPaint& paint) {
    580     int points = paint.countText(text, byteLength);
    581 
    582     // op + paint index + length + 'length' worth of data + num points + x&y point data
    583     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint);
    584 
    585     DrawType op = DRAW_POS_TEXT;
    586 
    587     size_t initialOffset = this->addDraw(op, &size);
    588     this->addPaint(paint);
    589     this->addText(text, byteLength);
    590     this->addInt(points);
    591     fWriter.writeMul4(pos, points * sizeof(SkPoint));
    592     this->validate(initialOffset, size);
    593 }
    594 
    595 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
    596                                      SkScalar constY, const SkPaint& paint) {
    597     int points = paint.countText(text, byteLength);
    598 
    599     // op + paint index + length + 'length' worth of data + num points
    600     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size;
    601     // + y + the actual points
    602     size += 1 * kUInt32Size + points * sizeof(SkScalar);
    603 
    604     size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size);
    605     this->addPaint(paint);
    606     this->addText(text, byteLength);
    607     this->addInt(points);
    608     this->addScalar(constY);
    609     fWriter.writeMul4(xpos, points * sizeof(SkScalar));
    610     this->validate(initialOffset, size);
    611 }
    612 
    613 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
    614                                        const SkMatrix* matrix, const SkPaint& paint) {
    615     // op + paint index + length + 'length' worth of data + path index + matrix
    616     const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
    617     size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(nullptr);
    618     size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size);
    619     this->addPaint(paint);
    620     this->addText(text, byteLength);
    621     this->addPath(path);
    622     this->addMatrix(m);
    623     this->validate(initialOffset, size);
    624 }
    625 
    626 void SkPictureRecord::onDrawTextRSXform(const void* text, size_t byteLength,
    627                                         const SkRSXform xform[], const SkRect* cull,
    628                                         const SkPaint& paint) {
    629     const int count = paint.countText(text, byteLength);
    630     // [op + paint-index + count + flags + length] + [text] + [xform] + cull
    631     size_t size = 5 * kUInt32Size + SkAlign4(byteLength) + count * sizeof(SkRSXform);
    632     uint32_t flags = 0;
    633     if (cull) {
    634         flags |= DRAW_TEXT_RSXFORM_HAS_CULL;
    635         size += sizeof(SkRect);
    636     }
    637 
    638     size_t initialOffset = this->addDraw(DRAW_TEXT_RSXFORM, &size);
    639     this->addPaint(paint);
    640     this->addInt(count);
    641     this->addInt(flags);
    642     this->addText(text, byteLength);
    643     fWriter.write(xform, count * sizeof(SkRSXform));
    644     if (cull) {
    645         fWriter.write(cull, sizeof(SkRect));
    646     }
    647     this->validate(initialOffset, size);
    648 }
    649 
    650 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
    651                                      const SkPaint& paint) {
    652 
    653     // op + paint index + blob index + x/y
    654     size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar);
    655     size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size);
    656 
    657     this->addPaint(paint);
    658     this->addTextBlob(blob);
    659     this->addScalar(x);
    660     this->addScalar(y);
    661 
    662     this->validate(initialOffset, size);
    663 }
    664 
    665 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
    666                                     const SkPaint* paint) {
    667     // op + picture index
    668     size_t size = 2 * kUInt32Size;
    669     size_t initialOffset;
    670 
    671     if (nullptr == matrix && nullptr == paint) {
    672         initialOffset = this->addDraw(DRAW_PICTURE, &size);
    673         this->addPicture(picture);
    674     } else {
    675         const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
    676         size += m.writeToMemory(nullptr) + kUInt32Size;    // matrix + paint
    677         initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
    678         this->addPaintPtr(paint);
    679         this->addMatrix(m);
    680         this->addPicture(picture);
    681     }
    682     this->validate(initialOffset, size);
    683 }
    684 
    685 void SkPictureRecord::onDrawShadowedPicture(const SkPicture* picture,
    686                                             const SkMatrix* matrix,
    687                                             const SkPaint* paint,
    688                                             const SkShadowParams& params) {
    689     // op + picture index
    690     size_t size = 2 * kUInt32Size;
    691     size_t initialOffset;
    692 
    693     // TODO: handle recording params.
    694     if (nullptr == matrix && nullptr == paint) {
    695         initialOffset = this->addDraw(DRAW_PICTURE, &size);
    696         this->addPicture(picture);
    697     } else {
    698         const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
    699         size += m.writeToMemory(nullptr) + kUInt32Size;    // matrix + paint
    700         initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
    701         this->addPaintPtr(paint);
    702         this->addMatrix(m);
    703         this->addPicture(picture);
    704     }
    705     this->validate(initialOffset, size);
    706 }
    707 
    708 void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
    709     // op + drawable index
    710     size_t size = 2 * kUInt32Size;
    711     size_t initialOffset;
    712 
    713     if (nullptr == matrix) {
    714         initialOffset = this->addDraw(DRAW_DRAWABLE, &size);
    715         this->addDrawable(drawable);
    716     } else {
    717         size += matrix->writeToMemory(nullptr);    // matrix
    718         initialOffset = this->addDraw(DRAW_DRAWABLE_MATRIX, &size);
    719         this->addMatrix(*matrix);
    720         this->addDrawable(drawable);
    721     }
    722     this->validate(initialOffset, size);
    723 }
    724 
    725 void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode,
    726                                            const SkPaint& paint) {
    727     // op + paint index + vertices index + mode
    728     size_t size = 4 * kUInt32Size;
    729     size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size);
    730 
    731     this->addPaint(paint);
    732     this->addVertices(vertices);
    733     this->addInt(static_cast<uint32_t>(mode));
    734 
    735     this->validate(initialOffset, size);
    736 }
    737 
    738 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
    739                                   const SkPoint texCoords[4], SkBlendMode bmode,
    740                                   const SkPaint& paint) {
    741     // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates
    742     size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size;
    743     uint32_t flag = 0;
    744     if (colors) {
    745         flag |= DRAW_VERTICES_HAS_COLORS;
    746         size += SkPatchUtils::kNumCorners * sizeof(SkColor);
    747     }
    748     if (texCoords) {
    749         flag |= DRAW_VERTICES_HAS_TEXS;
    750         size += SkPatchUtils::kNumCorners * sizeof(SkPoint);
    751     }
    752     if (SkBlendMode::kModulate != bmode) {
    753         flag |= DRAW_VERTICES_HAS_XFER;
    754         size += kUInt32Size;
    755     }
    756 
    757     size_t initialOffset = this->addDraw(DRAW_PATCH, &size);
    758     this->addPaint(paint);
    759     this->addPatch(cubics);
    760     this->addInt(flag);
    761 
    762     // write optional parameters
    763     if (colors) {
    764         fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
    765     }
    766     if (texCoords) {
    767         fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
    768     }
    769     if (flag & DRAW_VERTICES_HAS_XFER) {
    770         this->addInt((int)bmode);
    771     }
    772     this->validate(initialOffset, size);
    773 }
    774 
    775 void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[],
    776                                   const SkColor colors[], int count, SkBlendMode mode,
    777                                   const SkRect* cull, const SkPaint* paint) {
    778     // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
    779     size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
    780     uint32_t flags = 0;
    781     if (colors) {
    782         flags |= DRAW_ATLAS_HAS_COLORS;
    783         size += count * sizeof(SkColor);
    784         size += sizeof(uint32_t);   // xfermode::mode
    785     }
    786     if (cull) {
    787         flags |= DRAW_ATLAS_HAS_CULL;
    788         size += sizeof(SkRect);
    789     }
    790 
    791     size_t initialOffset = this->addDraw(DRAW_ATLAS, &size);
    792     this->addPaintPtr(paint);
    793     this->addImage(atlas);
    794     this->addInt(flags);
    795     this->addInt(count);
    796     fWriter.write(xform, count * sizeof(SkRSXform));
    797     fWriter.write(tex, count * sizeof(SkRect));
    798 
    799     // write optional parameters
    800     if (colors) {
    801         fWriter.write(colors, count * sizeof(SkColor));
    802         this->addInt((int)mode);
    803     }
    804     if (cull) {
    805         fWriter.write(cull, sizeof(SkRect));
    806     }
    807     this->validate(initialOffset, size);
    808 }
    809 
    810 void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) {
    811     size_t keyLen = fWriter.WriteStringSize(key);
    812     size_t valueLen = fWriter.WriteDataSize(value);
    813     size_t size = 4 + sizeof(SkRect) + keyLen + valueLen;
    814 
    815     size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size);
    816     this->addRect(rect);
    817     fWriter.writeString(key);
    818     fWriter.writeData(value);
    819     this->validate(initialOffset, size);
    820 }
    821 
    822 ///////////////////////////////////////////////////////////////////////////////
    823 
    824 template <typename T> int find_or_append_uniqueID(SkTDArray<const T*>& array, const T* obj) {
    825     int index = array.select([&](const T* elem) {
    826         return elem->uniqueID() == obj->uniqueID();
    827     });
    828     if (index < 0) {
    829         index = array.count();
    830         *array.append() = SkRef(obj);
    831     }
    832     return index;
    833 }
    834 
    835 sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) {
    836     return nullptr;
    837 }
    838 
    839 void SkPictureRecord::addImage(const SkImage* image) {
    840     // convention for images is 0-based index
    841     this->addInt(find_or_append_uniqueID(fImageRefs, image));
    842 }
    843 
    844 void SkPictureRecord::addMatrix(const SkMatrix& matrix) {
    845     fWriter.writeMatrix(matrix);
    846 }
    847 
    848 void SkPictureRecord::addPaintPtr(const SkPaint* paint) {
    849     fContentInfo.onAddPaintPtr(paint);
    850 
    851     if (paint) {
    852         fPaints.push_back(*paint);
    853         this->addInt(fPaints.count());
    854     } else {
    855         this->addInt(0);
    856     }
    857 }
    858 
    859 int SkPictureRecord::addPathToHeap(const SkPath& path) {
    860     if (int* n = fPaths.find(path)) {
    861         return *n;
    862     }
    863     int n = fPaths.count() + 1;  // 0 is reserved for null / error.
    864     fPaths.set(path, n);
    865     return n;
    866 }
    867 
    868 void SkPictureRecord::addPath(const SkPath& path) {
    869     this->addInt(this->addPathToHeap(path));
    870 }
    871 
    872 void SkPictureRecord::addPatch(const SkPoint cubics[12]) {
    873     fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
    874 }
    875 
    876 void SkPictureRecord::addPicture(const SkPicture* picture) {
    877     // follow the convention of recording a 1-based index
    878     this->addInt(find_or_append_uniqueID(fPictureRefs, picture) + 1);
    879 }
    880 
    881 void SkPictureRecord::addDrawable(SkDrawable* drawable) {
    882     int index = fDrawableRefs.find(drawable);
    883     if (index < 0) {    // not found
    884         index = fDrawableRefs.count();
    885         *fDrawableRefs.append() = drawable;
    886         drawable->ref();
    887     }
    888     // follow the convention of recording a 1-based index
    889     this->addInt(index + 1);
    890 }
    891 
    892 void SkPictureRecord::addPoint(const SkPoint& point) {
    893     fWriter.writePoint(point);
    894 }
    895 
    896 void SkPictureRecord::addPoints(const SkPoint pts[], int count) {
    897     fWriter.writeMul4(pts, count * sizeof(SkPoint));
    898 }
    899 
    900 void SkPictureRecord::addNoOp() {
    901     size_t size = kUInt32Size; // op
    902     this->addDraw(NOOP, &size);
    903 }
    904 
    905 void SkPictureRecord::addRect(const SkRect& rect) {
    906     fWriter.writeRect(rect);
    907 }
    908 
    909 void SkPictureRecord::addRectPtr(const SkRect* rect) {
    910     if (fWriter.writeBool(rect != nullptr)) {
    911         fWriter.writeRect(*rect);
    912     }
    913 }
    914 
    915 void SkPictureRecord::addIRect(const SkIRect& rect) {
    916     fWriter.write(&rect, sizeof(rect));
    917 }
    918 
    919 void SkPictureRecord::addIRectPtr(const SkIRect* rect) {
    920     if (fWriter.writeBool(rect != nullptr)) {
    921         *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect;
    922     }
    923 }
    924 
    925 void SkPictureRecord::addRRect(const SkRRect& rrect) {
    926     fWriter.writeRRect(rrect);
    927 }
    928 
    929 void SkPictureRecord::addRegion(const SkRegion& region) {
    930     fWriter.writeRegion(region);
    931 }
    932 
    933 void SkPictureRecord::addText(const void* text, size_t byteLength) {
    934     fContentInfo.onDrawText();
    935     addInt(SkToInt(byteLength));
    936     fWriter.writePad(text, byteLength);
    937 }
    938 
    939 void SkPictureRecord::addTextBlob(const SkTextBlob* blob) {
    940     // follow the convention of recording a 1-based index
    941     this->addInt(find_or_append_uniqueID(fTextBlobRefs, blob) + 1);
    942 }
    943 
    944 void SkPictureRecord::addVertices(const SkVertices* vertices) {
    945     // follow the convention of recording a 1-based index
    946     this->addInt(find_or_append_uniqueID(fVerticesRefs, vertices) + 1);
    947 }
    948 
    949 ///////////////////////////////////////////////////////////////////////////////
    950