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