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