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 */
26DrawType 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
43static const SkRect* get_rect_ptr(SkReader32* reader) {
44    if (reader->readBool()) {
45        return &reader->skipT<SkRect>();
46    } else {
47        return NULL;
48    }
49}
50
51class TextContainer {
52public:
53    size_t length() { return fByteLength; }
54    const void* text() { return (const void*)fText; }
55    size_t fByteLength;
56    const char* fText;
57};
58
59void 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.
65static SkBitmap shallow_copy(const SkBitmap& bitmap) {
66    return bitmap;
67}
68
69const 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.
82bool 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.
98void 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.
110void 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
132void 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
172void 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