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(®ion);
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