robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 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" |
dandov | b3c9d1c | 2014-08-12 08:34:29 -0700 | [diff] [blame] | 9 | #include "SkPatchUtils.h" |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 10 | #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 | |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 18 | /* |
robertphillips | 1ad00e4 | 2014-07-08 08:28:08 -0700 | [diff] [blame] | 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 | */ |
| 25 | DrawType SkPicturePlayback::ReadOpAndSize(SkReader32* reader, uint32_t* size) { |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 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 | |
robertphillips | 3afef1f | 2014-07-08 06:12:22 -0700 | [diff] [blame] | 42 | static const SkRect* get_rect_ptr(SkReader32* reader) { |
| 43 | if (reader->readBool()) { |
| 44 | return &reader->skipT<SkRect>(); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 45 | } else { |
| 46 | return NULL; |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | class TextContainer { |
| 51 | public: |
| 52 | size_t length() { return fByteLength; } |
| 53 | const void* text() { return (const void*)fText; } |
| 54 | size_t fByteLength; |
| 55 | const char* fText; |
| 56 | }; |
| 57 | |
| 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 | |
mtklein | eeb1f15 | 2014-07-07 16:17:36 -0700 | [diff] [blame] | 63 | // FIXME: SkBitmaps are stateful, so we need to copy them to play back in multiple threads. |
| 64 | static SkBitmap shallow_copy(const SkBitmap& bitmap) { |
| 65 | return bitmap; |
| 66 | } |
| 67 | |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 68 | const SkPicture::OperationList* SkPicturePlayback::getActiveOps(const SkCanvas* canvas) { |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 69 | |
robertphillips | 6142609 | 2014-07-10 09:35:12 -0700 | [diff] [blame] | 70 | if (fUseBBH) { |
robertphillips | 1ad00e4 | 2014-07-08 08:28:08 -0700 | [diff] [blame] | 71 | SkRect clipBounds; |
| 72 | if (canvas->getClipBounds(&clipBounds)) { |
| 73 | SkIRect query; |
| 74 | clipBounds.roundOut(&query); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 75 | |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 76 | 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. |
| 84 | bool 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 | |
robertphillips | 6142609 | 2014-07-10 09:35:12 -0700 | [diff] [blame] | 93 | fPictureData->initIterator(iter, activeOpsList->fOps, canvas); |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | return true; |
| 97 | } |
| 98 | |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 99 | // If 'iter' is valid use it to skip forward through the picture. |
| 100 | void 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); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 107 | } |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 108 | } |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | // Update the iterator and state tree to catch up with the skipped ops. |
| 112 | void 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 | |
| 134 | void 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); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 148 | |
| 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 | |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 154 | while (!reader.eof()) { |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 155 | if (NULL != callback && callback->abortDrawing()) { |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 156 | return; |
| 157 | } |
| 158 | |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 159 | fCurOffset = reader.offset(); |
| 160 | uint32_t size; |
robertphillips | 1ad00e4 | 2014-07-08 08:28:08 -0700 | [diff] [blame] | 161 | DrawType op = ReadOpAndSize(&reader, &size); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 162 | if (NOOP == op) { |
| 163 | // NOOPs are to be ignored - do not propagate them any further |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 164 | SkipIterTo(&it, &reader, fCurOffset + size); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 165 | continue; |
| 166 | } |
| 167 | |
robertphillips | 3afef1f | 2014-07-08 06:12:22 -0700 | [diff] [blame] | 168 | this->handleOp(&reader, op, size, canvas, initialMatrix); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 169 | |
robertphillips | ec66e62 | 2014-07-09 13:00:07 -0700 | [diff] [blame] | 170 | StepIterator(&it, &reader); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 171 | } |
robertphillips | 3afef1f | 2014-07-08 06:12:22 -0700 | [diff] [blame] | 172 | } |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 173 | |
robertphillips | 3afef1f | 2014-07-08 06:12:22 -0700 | [diff] [blame] | 174 | void 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(®ion); |
| 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; |
dandov | 963137b | 2014-08-07 07:49:53 -0700 | [diff] [blame] | 310 | case DRAW_PATCH: { |
| 311 | const SkPaint& paint = *fPictureData->getPaint(reader); |
dandov | b3c9d1c | 2014-08-12 08:34:29 -0700 | [diff] [blame] | 312 | |
| 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); |
dandov | 963137b | 2014-08-07 07:49:53 -0700 | [diff] [blame] | 334 | } break; |
robertphillips | 3afef1f | 2014-07-08 06:12:22 -0700 | [diff] [blame] | 335 | 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; |
reed | d5fa1a4 | 2014-08-09 11:08:05 -0700 | [diff] [blame] | 342 | case DRAW_PICTURE_MATRIX_PAINT: { |
fmalita | 9f49cfd | 2014-08-12 12:24:17 -0700 | [diff] [blame] | 343 | const SkPaint* paint = fPictureData->getPaint(reader); |
reed | d5fa1a4 | 2014-08-09 11:08:05 -0700 | [diff] [blame] | 344 | SkMatrix matrix; |
| 345 | reader->readMatrix(&matrix); |
fmalita | 9f49cfd | 2014-08-12 12:24:17 -0700 | [diff] [blame] | 346 | const SkPicture* pic = fPictureData->getPicture(reader); |
reed | d5fa1a4 | 2014-08-09 11:08:05 -0700 | [diff] [blame] | 347 | canvas->drawPicture(pic, &matrix, paint); |
| 348 | } break; |
robertphillips | 3afef1f | 2014-07-08 06:12:22 -0700 | [diff] [blame] | 349 | 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); |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 517 | } |
robertphillips | ce4dd3d | 2014-07-07 13:46:35 -0700 | [diff] [blame] | 518 | } |
| 519 | |