Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2014 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 "SkCanvas.h"
      9 #include "SkPatchUtils.h"
     10 #include "SkPictureData.h"
     11 #include "SkPicturePlayback.h"
     12 #include "SkPictureRecord.h"
     13 #include "SkPictureStateTree.h"
     14 #include "SkReader32.h"
     15 #include "SkTextBlob.h"
     16 #include "SkTDArray.h"
     17 #include "SkTypes.h"
     18 
     19 /*
     20  * Read the next op code and chunk size from 'reader'. The returned size
     21  * is the entire size of the chunk (including the opcode). Thus, the
     22  * offset just prior to calling ReadOpAndSize + 'size' is the offset
     23  * to the next chunk's op code. This also means that the size of a chunk
     24  * with no arguments (just an opcode) will be 4.
     25  */
     26 DrawType SkPicturePlayback::ReadOpAndSize(SkReader32* reader, uint32_t* size) {
     27     uint32_t temp = reader->readInt();
     28     uint32_t op;
     29     if (((uint8_t)temp) == temp) {
     30         // old skp file - no size information
     31         op = temp;
     32         *size = 0;
     33     } else {
     34         UNPACK_8_24(temp, op, *size);
     35         if (MASK_24 == *size) {
     36             *size = reader->readInt();
     37         }
     38     }
     39     return (DrawType)op;
     40 }
     41 
     42 
     43 static const SkRect* get_rect_ptr(SkReader32* reader) {
     44     if (reader->readBool()) {
     45         return &reader->skipT<SkRect>();
     46     } else {
     47         return NULL;
     48     }
     49 }
     50 
     51 class TextContainer {
     52 public:
     53     size_t length() { return fByteLength; }
     54     const void* text() { return (const void*)fText; }
     55     size_t fByteLength;
     56     const char* fText;
     57 };
     58 
     59 void get_text(SkReader32* reader, TextContainer* text) {
     60     size_t length = text->fByteLength = reader->readInt();
     61     text->fText = (const char*)reader->skip(length);
     62 }
     63 
     64 // FIXME: SkBitmaps are stateful, so we need to copy them to play back in multiple threads.
     65 static SkBitmap shallow_copy(const SkBitmap& bitmap) {
     66     return bitmap;
     67 }
     68 
     69 const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas* canvas) {
     70 
     71     if (fUseBBH) {
     72         SkRect clipBounds;
     73         if (canvas->getClipBounds(&clipBounds)) {
     74             return fPictureData->getActiveOps(clipBounds);
     75         }
     76     }
     77 
     78     return NULL;
     79 }
     80 
     81 // Initialize the state tree iterator. Return false if there is nothing left to draw.
     82 bool SkPicturePlayback::initIterator(SkPictureStateTree::Iterator* iter,
     83                                      SkCanvas* canvas,
     84                                      const SkPicture::OperationList *activeOpsList) {
     85 
     86     if (activeOpsList) {
     87         if (0 == activeOpsList->numOps()) {
     88             return false;  // nothing to draw
     89         }
     90 
     91         fPictureData->initIterator(iter, activeOpsList->fOps, canvas);
     92     }
     93 
     94     return true;
     95 }
     96 
     97 // If 'iter' is valid use it to skip forward through the picture.
     98 void SkPicturePlayback::StepIterator(SkPictureStateTree::Iterator* iter, SkReader32* reader) {
     99     if (iter->isValid()) {
    100         uint32_t skipTo = iter->nextDraw();
    101         if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) {
    102             reader->setOffset(reader->size());  // skip to end
    103         } else {
    104             reader->setOffset(skipTo);
    105         }
    106     }
    107 }
    108 
    109 // Update the iterator and state tree to catch up with the skipped ops.
    110 void SkPicturePlayback::SkipIterTo(SkPictureStateTree::Iterator* iter,
    111                                    SkReader32* reader,
    112                                    uint32_t skipTo) {
    113     SkASSERT(skipTo <= reader->size());
    114     SkASSERT(reader->offset() <= skipTo); // should only be skipping forward
    115 
    116     if (iter->isValid()) {
    117         // If using a bounding box hierarchy, advance the state tree
    118         // iterator until at or after skipTo
    119         uint32_t adjustedSkipTo;
    120         do {
    121             adjustedSkipTo = iter->nextDraw();
    122         } while (adjustedSkipTo < skipTo);
    123         skipTo = adjustedSkipTo;
    124     }
    125     if (SkPictureStateTree::Iterator::kDrawComplete == skipTo) {
    126         reader->setOffset(reader->size());  // skip to end
    127     } else {
    128         reader->setOffset(skipTo);
    129     }
    130 }
    131 
    132 void SkPicturePlayback::draw(SkCanvas* canvas, SkDrawPictureCallback* callback) {
    133     AutoResetOpID aroi(this);
    134     SkASSERT(0 == fCurOffset);
    135 
    136     SkAutoTDelete<const SkPicture::OperationList> activeOpsList(this->getActiveOps(canvas));
    137     SkPictureStateTree::Iterator it;
    138 
    139     if (!this->initIterator(&it, canvas, activeOpsList.get())) {
    140         return;  // nothing to draw
    141     }
    142 
    143     SkReader32 reader(fPictureData->opData()->bytes(), fPictureData->opData()->size());
    144 
    145     StepIterator(&it, &reader);
    146 
    147     // Record this, so we can concat w/ it if we encounter a setMatrix()
    148     SkMatrix initialMatrix = canvas->getTotalMatrix();
    149 
    150     SkAutoCanvasRestore acr(canvas, false);
    151 
    152     while (!reader.eof()) {
    153         if (callback && callback->abortDrawing()) {
    154             return;
    155         }
    156 
    157         fCurOffset = reader.offset();
    158         uint32_t size;
    159         DrawType op = ReadOpAndSize(&reader, &size);
    160         if (NOOP == op) {
    161             // NOOPs are to be ignored - do not propagate them any further
    162             SkipIterTo(&it, &reader, fCurOffset + size);
    163             continue;
    164         }
    165 
    166         this->handleOp(&reader, op, size, canvas, initialMatrix);
    167 
    168         StepIterator(&it, &reader);
    169     }
    170 }
    171 
    172 void SkPicturePlayback::handleOp(SkReader32* reader,
    173                                  DrawType op,
    174                                  uint32_t size,
    175                                  SkCanvas* canvas,
    176                                  const SkMatrix& initialMatrix) {
    177     switch (op) {
    178         case CLIP_PATH: {
    179             const SkPath& path = fPictureData->getPath(reader);
    180             uint32_t packed = reader->readInt();
    181             SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    182             bool doAA = ClipParams_unpackDoAA(packed);
    183             size_t offsetToRestore = reader->readInt();
    184             SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset());
    185             canvas->clipPath(path, regionOp, doAA);
    186             if (canvas->isClipEmpty() && offsetToRestore) {
    187                 reader->setOffset(offsetToRestore);
    188             }
    189         } break;
    190         case CLIP_REGION: {
    191             SkRegion region;
    192             reader->readRegion(&region);
    193             uint32_t packed = reader->readInt();
    194             SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    195             size_t offsetToRestore = reader->readInt();
    196             SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset());
    197             canvas->clipRegion(region, regionOp);
    198             if (canvas->isClipEmpty() && offsetToRestore) {
    199                 reader->setOffset(offsetToRestore);
    200             }
    201         } break;
    202         case CLIP_RECT: {
    203             const SkRect& rect = reader->skipT<SkRect>();
    204             uint32_t packed = reader->readInt();
    205             SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    206             bool doAA = ClipParams_unpackDoAA(packed);
    207             size_t offsetToRestore = reader->readInt();
    208             SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset());
    209             canvas->clipRect(rect, regionOp, doAA);
    210             if (canvas->isClipEmpty() && offsetToRestore) {
    211                 reader->setOffset(offsetToRestore);
    212             }
    213         } break;
    214         case CLIP_RRECT: {
    215             SkRRect rrect;
    216             reader->readRRect(&rrect);
    217             uint32_t packed = reader->readInt();
    218             SkRegion::Op regionOp = ClipParams_unpackRegionOp(packed);
    219             bool doAA = ClipParams_unpackDoAA(packed);
    220             size_t offsetToRestore = reader->readInt();
    221             SkASSERT(!offsetToRestore || offsetToRestore >= reader->offset());
    222             canvas->clipRRect(rrect, regionOp, doAA);
    223             if (canvas->isClipEmpty() && offsetToRestore) {
    224                 reader->setOffset(offsetToRestore);
    225             }
    226         } break;
    227         case PUSH_CULL: {
    228             const SkRect& cullRect = reader->skipT<SkRect>();
    229             size_t offsetToRestore = reader->readInt();
    230             if (offsetToRestore && canvas->quickReject(cullRect)) {
    231                 reader->setOffset(offsetToRestore);
    232             } else {
    233                 canvas->pushCull(cullRect);
    234             }
    235         } break;
    236         case POP_CULL:
    237             canvas->popCull();
    238             break;
    239         case CONCAT: {
    240             SkMatrix matrix;
    241             reader->readMatrix(&matrix);
    242             canvas->concat(matrix);
    243             break;
    244         }
    245         case DRAW_BITMAP: {
    246             const SkPaint* paint = fPictureData->getPaint(reader);
    247             const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
    248             const SkPoint& loc = reader->skipT<SkPoint>();
    249             canvas->drawBitmap(bitmap, loc.fX, loc.fY, paint);
    250         } break;
    251         case DRAW_BITMAP_RECT_TO_RECT: {
    252             const SkPaint* paint = fPictureData->getPaint(reader);
    253             const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
    254             const SkRect* src = get_rect_ptr(reader);   // may be null
    255             const SkRect& dst = reader->skipT<SkRect>();     // required
    256             SkCanvas::DrawBitmapRectFlags flags;
    257             flags = (SkCanvas::DrawBitmapRectFlags) reader->readInt();
    258             canvas->drawBitmapRectToRect(bitmap, src, dst, paint, flags);
    259         } break;
    260         case DRAW_BITMAP_MATRIX: {
    261             const SkPaint* paint = fPictureData->getPaint(reader);
    262             const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
    263             SkMatrix matrix;
    264             reader->readMatrix(&matrix);
    265             canvas->drawBitmapMatrix(bitmap, matrix, paint);
    266         } break;
    267         case DRAW_BITMAP_NINE: {
    268             const SkPaint* paint = fPictureData->getPaint(reader);
    269             const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
    270             const SkIRect& src = reader->skipT<SkIRect>();
    271             const SkRect& dst = reader->skipT<SkRect>();
    272             canvas->drawBitmapNine(bitmap, src, dst, paint);
    273         } break;
    274         case DRAW_CLEAR:
    275             canvas->clear(reader->readInt());
    276             break;
    277         case DRAW_DATA: {
    278             size_t length = reader->readInt();
    279             canvas->drawData(reader->skip(length), length);
    280             // skip handles padding the read out to a multiple of 4
    281         } break;
    282         case DRAW_DRRECT: {
    283             const SkPaint& paint = *fPictureData->getPaint(reader);
    284             SkRRect outer, inner;
    285             reader->readRRect(&outer);
    286             reader->readRRect(&inner);
    287             canvas->drawDRRect(outer, inner, paint);
    288         } break;
    289         case BEGIN_COMMENT_GROUP: {
    290             const char* desc = reader->readString();
    291             canvas->beginCommentGroup(desc);
    292         } break;
    293         case COMMENT: {
    294             const char* kywd = reader->readString();
    295             const char* value = reader->readString();
    296             canvas->addComment(kywd, value);
    297         } break;
    298         case END_COMMENT_GROUP: {
    299             canvas->endCommentGroup();
    300         } break;
    301         case DRAW_OVAL: {
    302             const SkPaint& paint = *fPictureData->getPaint(reader);
    303             canvas->drawOval(reader->skipT<SkRect>(), paint);
    304         } break;
    305         case DRAW_PAINT:
    306             canvas->drawPaint(*fPictureData->getPaint(reader));
    307             break;
    308         case DRAW_PATCH: {
    309             const SkPaint& paint = *fPictureData->getPaint(reader);
    310 
    311             const SkPoint* cubics = (const SkPoint*)reader->skip(SkPatchUtils::kNumCtrlPts *
    312                                                                  sizeof(SkPoint));
    313             uint32_t flag = reader->readInt();
    314             const SkColor* colors = NULL;
    315             if (flag & DRAW_VERTICES_HAS_COLORS) {
    316                 colors = (const SkColor*)reader->skip(SkPatchUtils::kNumCorners * sizeof(SkColor));
    317             }
    318             const SkPoint* texCoords = NULL;
    319             if (flag & DRAW_VERTICES_HAS_TEXS) {
    320                 texCoords = (const SkPoint*)reader->skip(SkPatchUtils::kNumCorners *
    321                                                          sizeof(SkPoint));
    322             }
    323             SkAutoTUnref<SkXfermode> xfer;
    324             if (flag & DRAW_VERTICES_HAS_XFER) {
    325                 int mode = reader->readInt();
    326                 if (mode < 0 || mode > SkXfermode::kLastMode) {
    327                     mode = SkXfermode::kModulate_Mode;
    328                 }
    329                 xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
    330             }
    331             canvas->drawPatch(cubics, colors, texCoords, xfer, paint);
    332         } break;
    333         case DRAW_PATH: {
    334             const SkPaint& paint = *fPictureData->getPaint(reader);
    335             canvas->drawPath(fPictureData->getPath(reader), paint);
    336         } break;
    337         case DRAW_PICTURE:
    338             canvas->drawPicture(fPictureData->getPicture(reader));
    339             break;
    340         case DRAW_PICTURE_MATRIX_PAINT: {
    341             const SkPaint* paint = fPictureData->getPaint(reader);
    342             SkMatrix matrix;
    343             reader->readMatrix(&matrix);
    344             const SkPicture* pic = fPictureData->getPicture(reader);
    345             canvas->drawPicture(pic, &matrix, paint);
    346         } break;
    347         case DRAW_POINTS: {
    348             const SkPaint& paint = *fPictureData->getPaint(reader);
    349             SkCanvas::PointMode mode = (SkCanvas::PointMode)reader->readInt();
    350             size_t count = reader->readInt();
    351             const SkPoint* pts = (const SkPoint*)reader->skip(sizeof(SkPoint)* count);
    352             canvas->drawPoints(mode, count, pts, paint);
    353         } break;
    354         case DRAW_POS_TEXT: {
    355             const SkPaint& paint = *fPictureData->getPaint(reader);
    356             TextContainer text;
    357             get_text(reader, &text);
    358             size_t points = reader->readInt();
    359             const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint));
    360             canvas->drawPosText(text.text(), text.length(), pos, paint);
    361         } break;
    362         case DRAW_POS_TEXT_TOP_BOTTOM: {
    363             const SkPaint& paint = *fPictureData->getPaint(reader);
    364             TextContainer text;
    365             get_text(reader, &text);
    366             size_t points = reader->readInt();
    367             const SkPoint* pos = (const SkPoint*)reader->skip(points * sizeof(SkPoint));
    368             const SkScalar top = reader->readScalar();
    369             const SkScalar bottom = reader->readScalar();
    370             if (!canvas->quickRejectY(top, bottom)) {
    371                 canvas->drawPosText(text.text(), text.length(), pos, paint);
    372             }
    373         } break;
    374         case DRAW_POS_TEXT_H: {
    375             const SkPaint& paint = *fPictureData->getPaint(reader);
    376             TextContainer text;
    377             get_text(reader, &text);
    378             size_t xCount = reader->readInt();
    379             const SkScalar constY = reader->readScalar();
    380             const SkScalar* xpos = (const SkScalar*)reader->skip(xCount * sizeof(SkScalar));
    381             canvas->drawPosTextH(text.text(), text.length(), xpos, constY, paint);
    382         } break;
    383         case DRAW_POS_TEXT_H_TOP_BOTTOM: {
    384             const SkPaint& paint = *fPictureData->getPaint(reader);
    385             TextContainer text;
    386             get_text(reader, &text);
    387             size_t xCount = reader->readInt();
    388             const SkScalar* xpos = (const SkScalar*)reader->skip((3 + xCount) * sizeof(SkScalar));
    389             const SkScalar top = *xpos++;
    390             const SkScalar bottom = *xpos++;
    391             const SkScalar constY = *xpos++;
    392             if (!canvas->quickRejectY(top, bottom)) {
    393                 canvas->drawPosTextH(text.text(), text.length(), xpos, constY, paint);
    394             }
    395         } break;
    396         case DRAW_RECT: {
    397             const SkPaint& paint = *fPictureData->getPaint(reader);
    398             canvas->drawRect(reader->skipT<SkRect>(), paint);
    399         } break;
    400         case DRAW_RRECT: {
    401             const SkPaint& paint = *fPictureData->getPaint(reader);
    402             SkRRect rrect;
    403             reader->readRRect(&rrect);
    404             canvas->drawRRect(rrect, paint);
    405         } break;
    406         case DRAW_SPRITE: {
    407             const SkPaint* paint = fPictureData->getPaint(reader);
    408             const SkBitmap bitmap = shallow_copy(fPictureData->getBitmap(reader));
    409             int left = reader->readInt();
    410             int top = reader->readInt();
    411             canvas->drawSprite(bitmap, left, top, paint);
    412         } break;
    413         case DRAW_TEXT: {
    414             const SkPaint& paint = *fPictureData->getPaint(reader);
    415             TextContainer text;
    416             get_text(reader, &text);
    417             SkScalar x = reader->readScalar();
    418             SkScalar y = reader->readScalar();
    419             canvas->drawText(text.text(), text.length(), x, y, paint);
    420         } break;
    421         case DRAW_TEXT_BLOB: {
    422             const SkPaint& paint = *fPictureData->getPaint(reader);
    423             const SkTextBlob* blob = fPictureData->getTextBlob(reader);
    424             SkScalar x = reader->readScalar();
    425             SkScalar y = reader->readScalar();
    426             canvas->drawTextBlob(blob, x, y, paint);
    427         } break;
    428         case DRAW_TEXT_TOP_BOTTOM: {
    429             const SkPaint& paint = *fPictureData->getPaint(reader);
    430             TextContainer text;
    431             get_text(reader, &text);
    432             const SkScalar* ptr = (const SkScalar*)reader->skip(4 * sizeof(SkScalar));
    433             // ptr[0] == x
    434             // ptr[1] == y
    435             // ptr[2] == top
    436             // ptr[3] == bottom
    437             if (!canvas->quickRejectY(ptr[2], ptr[3])) {
    438                 canvas->drawText(text.text(), text.length(), ptr[0], ptr[1], paint);
    439             }
    440         } break;
    441         case DRAW_TEXT_ON_PATH: {
    442             const SkPaint& paint = *fPictureData->getPaint(reader);
    443             TextContainer text;
    444             get_text(reader, &text);
    445             const SkPath& path = fPictureData->getPath(reader);
    446             SkMatrix matrix;
    447             reader->readMatrix(&matrix);
    448             canvas->drawTextOnPath(text.text(), text.length(), path, &matrix, paint);
    449         } break;
    450         case DRAW_VERTICES: {
    451             SkAutoTUnref<SkXfermode> xfer;
    452             const SkPaint& paint = *fPictureData->getPaint(reader);
    453             DrawVertexFlags flags = (DrawVertexFlags)reader->readInt();
    454             SkCanvas::VertexMode vmode = (SkCanvas::VertexMode)reader->readInt();
    455             int vCount = reader->readInt();
    456             const SkPoint* verts = (const SkPoint*)reader->skip(vCount * sizeof(SkPoint));
    457             const SkPoint* texs = NULL;
    458             const SkColor* colors = NULL;
    459             const uint16_t* indices = NULL;
    460             int iCount = 0;
    461             if (flags & DRAW_VERTICES_HAS_TEXS) {
    462                 texs = (const SkPoint*)reader->skip(vCount * sizeof(SkPoint));
    463             }
    464             if (flags & DRAW_VERTICES_HAS_COLORS) {
    465                 colors = (const SkColor*)reader->skip(vCount * sizeof(SkColor));
    466             }
    467             if (flags & DRAW_VERTICES_HAS_INDICES) {
    468                 iCount = reader->readInt();
    469                 indices = (const uint16_t*)reader->skip(iCount * sizeof(uint16_t));
    470             }
    471             if (flags & DRAW_VERTICES_HAS_XFER) {
    472                 int mode = reader->readInt();
    473                 if (mode < 0 || mode > SkXfermode::kLastMode) {
    474                     mode = SkXfermode::kModulate_Mode;
    475                 }
    476                 xfer.reset(SkXfermode::Create((SkXfermode::Mode)mode));
    477             }
    478             canvas->drawVertices(vmode, vCount, verts, texs, colors, xfer, indices, iCount, paint);
    479         } break;
    480         case RESTORE:
    481             canvas->restore();
    482             break;
    483         case ROTATE:
    484             canvas->rotate(reader->readScalar());
    485             break;
    486         case SAVE:
    487             // SKPs with version < 29 also store a SaveFlags param.
    488             if (size > 4) {
    489                 SkASSERT(8 == size);
    490                 reader->readInt();
    491             }
    492             canvas->save();
    493             break;
    494         case SAVE_LAYER: {
    495             const SkRect* boundsPtr = get_rect_ptr(reader);
    496             const SkPaint* paint = fPictureData->getPaint(reader);
    497             canvas->saveLayer(boundsPtr, paint, (SkCanvas::SaveFlags) reader->readInt());
    498         } break;
    499         case SCALE: {
    500             SkScalar sx = reader->readScalar();
    501             SkScalar sy = reader->readScalar();
    502             canvas->scale(sx, sy);
    503         } break;
    504         case SET_MATRIX: {
    505             SkMatrix matrix;
    506             reader->readMatrix(&matrix);
    507             matrix.postConcat(initialMatrix);
    508             canvas->setMatrix(matrix);
    509         } break;
    510         case SKEW: {
    511             SkScalar sx = reader->readScalar();
    512             SkScalar sy = reader->readScalar();
    513             canvas->skew(sx, sy);
    514         } break;
    515         case TRANSLATE: {
    516             SkScalar dx = reader->readScalar();
    517             SkScalar dy = reader->readScalar();
    518             canvas->translate(dx, dy);
    519         } break;
    520         default:
    521             SkASSERT(0);
    522     }
    523 }
    524 
    525