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