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