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