1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SkPictureRecord.h" 9 #include "SkTSearch.h" 10 #include "SkPixelRef.h" 11 #include "SkRRect.h" 12 #include "SkBBoxHierarchy.h" 13 #include "SkDevice.h" 14 #include "SkPictureStateTree.h" 15 16 #define MIN_WRITER_SIZE 16384 17 #define HEAP_BLOCK_SIZE 4096 18 19 enum { 20 // just need a value that save or getSaveCount would never return 21 kNoInitialSave = -1, 22 }; 23 24 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc. 25 static int const kUInt32Size = 4; 26 27 static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; 28 static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect); 29 30 SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) : 31 INHERITED(device), 32 fBoundingHierarchy(NULL), 33 fStateTree(NULL), 34 fFlattenableHeap(HEAP_BLOCK_SIZE), 35 fMatrices(&fFlattenableHeap), 36 fPaints(&fFlattenableHeap), 37 fRegions(&fFlattenableHeap), 38 fWriter(MIN_WRITER_SIZE), 39 fRecordFlags(flags) { 40 #ifdef SK_DEBUG_SIZE 41 fPointBytes = fRectBytes = fTextBytes = 0; 42 fPointWrites = fRectWrites = fTextWrites = 0; 43 #endif 44 45 fRestoreOffsetStack.setReserve(32); 46 47 fBitmapHeap = SkNEW(SkBitmapHeap); 48 fFlattenableHeap.setBitmapStorage(fBitmapHeap); 49 fPathHeap = NULL; // lazy allocate 50 fFirstSavedLayerIndex = kNoSavedLayerIndex; 51 52 fInitialSaveCount = kNoInitialSave; 53 } 54 55 SkPictureRecord::~SkPictureRecord() { 56 SkSafeUnref(fBitmapHeap); 57 SkSafeUnref(fPathHeap); 58 SkSafeUnref(fBoundingHierarchy); 59 SkSafeUnref(fStateTree); 60 fFlattenableHeap.setBitmapStorage(NULL); 61 fPictureRefs.unrefAll(); 62 } 63 64 /////////////////////////////////////////////////////////////////////////////// 65 66 // Return the offset of the paint inside a given op's byte stream. A zero 67 // return value means there is no paint (and you really shouldn't be calling 68 // this method) 69 static inline uint32_t getPaintOffset(DrawType op, uint32_t opSize) { 70 // These offsets are where the paint would be if the op size doesn't overflow 71 static const uint8_t gPaintOffsets[LAST_DRAWTYPE_ENUM + 1] = { 72 0, // UNUSED - no paint 73 0, // CLIP_PATH - no paint 74 0, // CLIP_REGION - no paint 75 0, // CLIP_RECT - no paint 76 0, // CLIP_RRECT - no paint 77 0, // CONCAT - no paint 78 1, // DRAW_BITMAP - right after op code 79 1, // DRAW_BITMAP_MATRIX - right after op code 80 1, // DRAW_BITMAP_NINE - right after op code 81 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code 82 0, // DRAW_CLEAR - no paint 83 0, // DRAW_DATA - no paint 84 1, // DRAW_OVAL - right after op code 85 1, // DRAW_PAINT - right after op code 86 1, // DRAW_PATH - right after op code 87 0, // DRAW_PICTURE - no paint 88 1, // DRAW_POINTS - right after op code 89 1, // DRAW_POS_TEXT - right after op code 90 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code 91 1, // DRAW_POS_TEXT_H - right after op code 92 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code 93 1, // DRAW_RECT - right after op code 94 1, // DRAW_RRECT - right after op code 95 1, // DRAW_SPRITE - right after op code 96 1, // DRAW_TEXT - right after op code 97 1, // DRAW_TEXT_ON_PATH - right after op code 98 1, // DRAW_TEXT_TOP_BOTTOM - right after op code 99 1, // DRAW_VERTICES - right after op code 100 0, // RESTORE - no paint 101 0, // ROTATE - no paint 102 0, // SAVE - no paint 103 0, // SAVE_LAYER - see below - this paint's location varies 104 0, // SCALE - no paint 105 0, // SET_MATRIX - no paint 106 0, // SKEW - no paint 107 0, // TRANSLATE - no paint 108 0, // NOOP - no paint 109 0, // BEGIN_GROUP - no paint 110 0, // COMMENT - no paint 111 0, // END_GROUP - no paint 112 }; 113 114 SkASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1); 115 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM); 116 117 int overflow = 0; 118 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) { 119 // This op's size overflows so an extra uint32_t will be written 120 // after the op code 121 overflow = sizeof(uint32_t); 122 } 123 124 if (SAVE_LAYER == op) { 125 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size; 126 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect); 127 128 if (kSaveLayerNoBoundsSize == opSize) { 129 return kSaveLayerNoBoundsPaintOffset + overflow; 130 } else { 131 SkASSERT(kSaveLayerWithBoundsSize == opSize); 132 return kSaveLayerWithBoundsPaintOffset + overflow; 133 } 134 } 135 136 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method 137 return gPaintOffsets[op] * sizeof(uint32_t) + overflow; 138 } 139 140 SkDevice* SkPictureRecord::setDevice(SkDevice* device) { 141 SkASSERT(!"eeek, don't try to change the device on a recording canvas"); 142 return this->INHERITED::setDevice(device); 143 } 144 145 int SkPictureRecord::save(SaveFlags flags) { 146 // record the offset to us, making it non-positive to distinguish a save 147 // from a clip entry. 148 fRestoreOffsetStack.push(-(int32_t)fWriter.size()); 149 150 // op + flags 151 uint32_t size = 2 * kUInt32Size; 152 uint32_t initialOffset = this->addDraw(SAVE, &size); 153 addInt(flags); 154 155 validate(initialOffset, size); 156 return this->INHERITED::save(flags); 157 } 158 159 int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint, 160 SaveFlags flags) { 161 // record the offset to us, making it non-positive to distinguish a save 162 // from a clip entry. 163 fRestoreOffsetStack.push(-(int32_t)fWriter.size()); 164 165 // op + bool for 'bounds' 166 uint32_t size = 2 * kUInt32Size; 167 if (NULL != bounds) { 168 size += sizeof(*bounds); // + rect 169 } 170 // + paint index + flags 171 size += 2 * kUInt32Size; 172 173 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size); 174 175 uint32_t initialOffset = this->addDraw(SAVE_LAYER, &size); 176 addRectPtr(bounds); 177 SkASSERT(initialOffset+getPaintOffset(SAVE_LAYER, size) == fWriter.size()); 178 addPaintPtr(paint); 179 addInt(flags); 180 181 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) { 182 fFirstSavedLayerIndex = fRestoreOffsetStack.count(); 183 } 184 185 validate(initialOffset, size); 186 /* Don't actually call saveLayer, because that will try to allocate an 187 offscreen device (potentially very big) which we don't actually need 188 at this time (and may not be able to afford since during record our 189 clip starts out the size of the picture, which is often much larger 190 than the size of the actual device we'll use during playback). 191 */ 192 int count = this->INHERITED::save(flags); 193 this->clipRectBounds(bounds, flags, NULL); 194 return count; 195 } 196 197 bool SkPictureRecord::isDrawingToLayer() const { 198 return fFirstSavedLayerIndex != kNoSavedLayerIndex; 199 } 200 201 /* 202 * Read the op code from 'offset' in 'writer' and extract the size too. 203 */ 204 static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) { 205 uint32_t* peek = writer->peek32(offset); 206 207 uint32_t op; 208 UNPACK_8_24(*peek, op, *size); 209 if (MASK_24 == *size) { 210 // size required its own slot right after the op code 211 *size = *writer->peek32(offset+kUInt32Size); 212 } 213 return (DrawType) op; 214 } 215 216 #ifdef TRACK_COLLAPSE_STATS 217 static int gCollapseCount, gCollapseCalls; 218 #endif 219 220 // Is the supplied paint simply a color? 221 static bool is_simple(const SkPaint& p) { 222 intptr_t orAccum = (intptr_t)p.getPathEffect() | 223 (intptr_t)p.getShader() | 224 (intptr_t)p.getXfermode() | 225 (intptr_t)p.getMaskFilter() | 226 (intptr_t)p.getColorFilter() | 227 (intptr_t)p.getRasterizer() | 228 (intptr_t)p.getLooper() | 229 (intptr_t)p.getImageFilter(); 230 return 0 == orAccum; 231 } 232 233 // CommandInfos are fed to the 'match' method and filled in with command 234 // information. 235 struct CommandInfo { 236 DrawType fActualOp; 237 uint32_t fOffset; 238 uint32_t fSize; 239 }; 240 241 /* 242 * Attempt to match the provided pattern of commands starting at 'offset' 243 * in the byte stream and stopping at the end of the stream. Upon success, 244 * return true with all the pattern information filled out in the result 245 * array (i.e., actual ops, offsets and sizes). 246 * Note this method skips any NOOPs seen in the stream 247 */ 248 static bool match(SkWriter32* writer, uint32_t offset, 249 int* pattern, CommandInfo* result, int numCommands) { 250 SkASSERT(offset < writer->size()); 251 252 uint32_t curOffset = offset; 253 uint32_t curSize = 0; 254 int numMatched; 255 for (numMatched = 0; numMatched < numCommands && curOffset < writer->size(); ++numMatched) { 256 DrawType op = peek_op_and_size(writer, curOffset, &curSize); 257 while (NOOP == op && curOffset < writer->size()) { 258 curOffset += curSize; 259 op = peek_op_and_size(writer, curOffset, &curSize); 260 } 261 262 if (curOffset >= writer->size()) { 263 return false; // ran out of byte stream 264 } 265 266 if (kDRAW_BITMAP_FLAVOR == pattern[numMatched]) { 267 if (DRAW_BITMAP != op && DRAW_BITMAP_MATRIX != op && 268 DRAW_BITMAP_NINE != op && DRAW_BITMAP_RECT_TO_RECT != op) { 269 return false; 270 } 271 } else if (op != pattern[numMatched]) { 272 return false; 273 } 274 275 result[numMatched].fActualOp = op; 276 result[numMatched].fOffset = curOffset; 277 result[numMatched].fSize = curSize; 278 279 curOffset += curSize; 280 } 281 282 if (numMatched != numCommands) { 283 return false; 284 } 285 286 curOffset += curSize; 287 if (curOffset < writer->size()) { 288 // Something else between the last command and the end of the stream 289 return false; 290 } 291 292 return true; 293 } 294 295 // temporarily here to make code review easier 296 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, 297 SkPaintDictionary* paintDict, 298 const CommandInfo& saveLayerInfo, 299 const CommandInfo& dbmInfo); 300 301 /* 302 * Restore has just been called (but not recorded), look back at the 303 * matching save* and see if we are in the configuration: 304 * SAVE_LAYER 305 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT 306 * RESTORE 307 * where the saveLayer's color can be moved into the drawBitmap*'s paint 308 */ 309 static bool remove_save_layer1(SkWriter32* writer, int32_t offset, 310 SkPaintDictionary* paintDict) { 311 // back up to the save block 312 // TODO: add a stack to track save*/restore offsets rather than searching backwards 313 while (offset > 0) { 314 offset = *writer->peek32(offset); 315 } 316 317 int pattern[] = { SAVE_LAYER, kDRAW_BITMAP_FLAVOR, /* RESTORE */ }; 318 CommandInfo result[SK_ARRAY_COUNT(pattern)]; 319 320 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { 321 return false; 322 } 323 324 if (kSaveLayerWithBoundsSize == result[0].fSize) { 325 // The saveLayer's bound can offset where the dbm is drawn 326 return false; 327 } 328 329 330 return merge_savelayer_paint_into_drawbitmp(writer, paintDict, 331 result[0], result[1]); 332 } 333 334 /* 335 * Convert the command code located at 'offset' to a NOOP. Leave the size 336 * field alone so the NOOP can be skipped later. 337 */ 338 static void convert_command_to_noop(SkWriter32* writer, uint32_t offset) { 339 uint32_t* ptr = writer->peek32(offset); 340 *ptr = (*ptr & MASK_24) | (NOOP << 24); 341 } 342 343 /* 344 * Attempt to merge the saveLayer's paint into the drawBitmap*'s paint. 345 * Return true on success; false otherwise. 346 */ 347 static bool merge_savelayer_paint_into_drawbitmp(SkWriter32* writer, 348 SkPaintDictionary* paintDict, 349 const CommandInfo& saveLayerInfo, 350 const CommandInfo& dbmInfo) { 351 SkASSERT(SAVE_LAYER == saveLayerInfo.fActualOp); 352 SkASSERT(DRAW_BITMAP == dbmInfo.fActualOp || 353 DRAW_BITMAP_MATRIX == dbmInfo.fActualOp || 354 DRAW_BITMAP_NINE == dbmInfo.fActualOp || 355 DRAW_BITMAP_RECT_TO_RECT == dbmInfo.fActualOp); 356 357 uint32_t dbmPaintOffset = getPaintOffset(dbmInfo.fActualOp, dbmInfo.fSize); 358 uint32_t slPaintOffset = getPaintOffset(SAVE_LAYER, saveLayerInfo.fSize); 359 360 // we have a match, now we need to get the paints involved 361 uint32_t dbmPaintId = *writer->peek32(dbmInfo.fOffset+dbmPaintOffset); 362 uint32_t saveLayerPaintId = *writer->peek32(saveLayerInfo.fOffset+slPaintOffset); 363 364 if (0 == saveLayerPaintId) { 365 // In this case the saveLayer/restore isn't needed at all - just kill the saveLayer 366 // and signal the caller (by returning true) to not add the RESTORE op 367 convert_command_to_noop(writer, saveLayerInfo.fOffset); 368 return true; 369 } 370 371 if (0 == dbmPaintId) { 372 // In this case just make the DBM* use the saveLayer's paint, kill the saveLayer 373 // and signal the caller (by returning true) to not add the RESTORE op 374 convert_command_to_noop(writer, saveLayerInfo.fOffset); 375 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset); 376 SkASSERT(0 == *ptr); 377 *ptr = saveLayerPaintId; 378 return true; 379 } 380 381 SkAutoTDelete<SkPaint> saveLayerPaint(paintDict->unflatten(saveLayerPaintId)); 382 if (NULL == saveLayerPaint.get() || !is_simple(*saveLayerPaint)) { 383 return false; 384 } 385 386 // For this optimization we only fold the saveLayer and drawBitmapRect 387 // together if the saveLayer's draw is simple (i.e., no fancy effects) and 388 // and the only difference in the colors is that the saveLayer's can have 389 // an alpha while the drawBitmapRect's is opaque. 390 // TODO: it should be possible to fold them together even if they both 391 // have different non-255 alphas 392 SkColor layerColor = saveLayerPaint->getColor() | 0xFF000000; // force opaque 393 394 SkAutoTDelete<SkPaint> dbmPaint(paintDict->unflatten(dbmPaintId)); 395 if (NULL == dbmPaint.get() || dbmPaint->getColor() != layerColor) { 396 return false; 397 } 398 399 SkColor newColor = SkColorSetA(dbmPaint->getColor(), 400 SkColorGetA(saveLayerPaint->getColor())); 401 dbmPaint->setColor(newColor); 402 403 const SkFlatData* data = paintDict->findAndReturnFlat(*dbmPaint); 404 if (NULL == data) { 405 return false; 406 } 407 408 // kill the saveLayer and alter the DBMR2R's paint to be the modified one 409 convert_command_to_noop(writer, saveLayerInfo.fOffset); 410 uint32_t* ptr = writer->peek32(dbmInfo.fOffset+dbmPaintOffset); 411 SkASSERT(dbmPaintId == *ptr); 412 *ptr = data->index(); 413 return true; 414 } 415 416 /* 417 * Restore has just been called (but not recorded), look back at the 418 * matching save* and see if we are in the configuration: 419 * SAVE_LAYER (with NULL == bounds) 420 * SAVE 421 * CLIP_RECT 422 * DRAW_BITMAP|DRAW_BITMAP_MATRIX|DRAW_BITMAP_NINE|DRAW_BITMAP_RECT_TO_RECT 423 * RESTORE 424 * RESTORE 425 * where the saveLayer's color can be moved into the drawBitmap*'s paint 426 */ 427 static bool remove_save_layer2(SkWriter32* writer, int32_t offset, 428 SkPaintDictionary* paintDict) { 429 430 // back up to the save block 431 // TODO: add a stack to track save*/restore offsets rather than searching backwards 432 while (offset > 0) { 433 offset = *writer->peek32(offset); 434 } 435 436 int pattern[] = { SAVE_LAYER, SAVE, CLIP_RECT, kDRAW_BITMAP_FLAVOR, RESTORE, /* RESTORE */ }; 437 CommandInfo result[SK_ARRAY_COUNT(pattern)]; 438 439 if (!match(writer, -offset, pattern, result, SK_ARRAY_COUNT(pattern))) { 440 return false; 441 } 442 443 if (kSaveLayerWithBoundsSize == result[0].fSize) { 444 // The saveLayer's bound can offset where the dbm is drawn 445 return false; 446 } 447 448 return merge_savelayer_paint_into_drawbitmp(writer, paintDict, 449 result[0], result[3]); 450 } 451 452 /* 453 * Restore has just been called (but not recorded), so look back at the 454 * matching save(), and see if we can eliminate the pair of them, due to no 455 * intervening matrix/clip calls. 456 * 457 * If so, update the writer and return true, in which case we won't even record 458 * the restore() call. If we still need the restore(), return false. 459 */ 460 static bool collapse_save_clip_restore(SkWriter32* writer, int32_t offset, 461 SkPaintDictionary* paintDict) { 462 #ifdef TRACK_COLLAPSE_STATS 463 gCollapseCalls += 1; 464 #endif 465 466 int32_t restoreOffset = (int32_t)writer->size(); 467 468 // back up to the save block 469 while (offset > 0) { 470 offset = *writer->peek32(offset); 471 } 472 473 // now offset points to a save 474 offset = -offset; 475 uint32_t opSize; 476 DrawType op = peek_op_and_size(writer, offset, &opSize); 477 if (SAVE_LAYER == op) { 478 // not ready to cull these out yet (mrr) 479 return false; 480 } 481 SkASSERT(SAVE == op); 482 483 // Walk forward until we get back to either a draw-verb (abort) or we hit 484 // our restore (success). 485 int32_t saveOffset = offset; 486 487 offset += opSize; 488 while (offset < restoreOffset) { 489 op = peek_op_and_size(writer, offset, &opSize); 490 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) { 491 // drawing verb, abort 492 return false; 493 } 494 offset += opSize; 495 } 496 497 #ifdef TRACK_COLLAPSE_STATS 498 gCollapseCount += 1; 499 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls, 500 (double)gCollapseCount / gCollapseCalls, "%"); 501 #endif 502 503 writer->rewindToOffset(saveOffset); 504 return true; 505 } 506 507 typedef bool (*PictureRecordOptProc)(SkWriter32* writer, int32_t offset, 508 SkPaintDictionary* paintDict); 509 enum PictureRecordOptType { 510 kRewind_OptType, // Optimization rewinds the command stream 511 kCollapseSaveLayer_OptType, // Optimization eliminates a save/restore pair 512 }; 513 514 struct PictureRecordOpt { 515 PictureRecordOptProc fProc; 516 PictureRecordOptType fType; 517 }; 518 /* 519 * A list of the optimizations that are tried upon seeing a restore 520 * TODO: add a real API for such optimizations 521 * Add the ability to fire optimizations on any op (not just RESTORE) 522 */ 523 static const PictureRecordOpt gPictureRecordOpts[] = { 524 { collapse_save_clip_restore, kRewind_OptType }, 525 { remove_save_layer1, kCollapseSaveLayer_OptType }, 526 { remove_save_layer2, kCollapseSaveLayer_OptType } 527 }; 528 529 // This is called after an optimization has been applied to the command stream 530 // in order to adjust the contents and state of the bounding box hierarchy and 531 // state tree to reflect the optimization. 532 static void apply_optimization_to_bbh(PictureRecordOptType opt, SkPictureStateTree* stateTree, 533 SkBBoxHierarchy* boundingHierarchy) { 534 switch (opt) { 535 case kCollapseSaveLayer_OptType: 536 if (NULL != stateTree) { 537 stateTree->saveCollapsed(); 538 } 539 break; 540 case kRewind_OptType: 541 if (NULL != boundingHierarchy) { 542 boundingHierarchy->rewindInserts(); 543 } 544 // Note: No need to touch the state tree for this to work correctly. 545 // Unused branches do not burden the playback, and pruning the tree 546 // would be O(N^2), so it is best to leave it alone. 547 break; 548 default: 549 SkASSERT(0); 550 } 551 } 552 553 void SkPictureRecord::restore() { 554 // FIXME: SkDeferredCanvas needs to be refactored to respect 555 // save/restore balancing so that the following test can be 556 // turned on permanently. 557 #if 0 558 SkASSERT(fRestoreOffsetStack.count() > 1); 559 #endif 560 561 // check for underflow 562 if (fRestoreOffsetStack.count() == 0) { 563 return; 564 } 565 566 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) { 567 fFirstSavedLayerIndex = kNoSavedLayerIndex; 568 } 569 570 uint32_t initialOffset, size; 571 size_t opt = 0; 572 if (!(fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag)) { 573 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) { 574 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) { 575 // Some optimization fired so don't add the RESTORE 576 size = 0; 577 initialOffset = fWriter.size(); 578 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType, 579 fStateTree, fBoundingHierarchy); 580 break; 581 } 582 } 583 } 584 585 if ((fRecordFlags & SkPicture::kDisableRecordOptimizations_RecordingFlag) || 586 SK_ARRAY_COUNT(gPictureRecordOpts) == opt) { 587 // No optimization fired so add the RESTORE 588 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size()); 589 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code 590 initialOffset = this->addDraw(RESTORE, &size); 591 } 592 593 fRestoreOffsetStack.pop(); 594 595 validate(initialOffset, size); 596 return this->INHERITED::restore(); 597 } 598 599 bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) { 600 // op + dx + dy 601 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 602 uint32_t initialOffset = this->addDraw(TRANSLATE, &size); 603 addScalar(dx); 604 addScalar(dy); 605 validate(initialOffset, size); 606 return this->INHERITED::translate(dx, dy); 607 } 608 609 bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) { 610 // op + sx + sy 611 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 612 uint32_t initialOffset = this->addDraw(SCALE, &size); 613 addScalar(sx); 614 addScalar(sy); 615 validate(initialOffset, size); 616 return this->INHERITED::scale(sx, sy); 617 } 618 619 bool SkPictureRecord::rotate(SkScalar degrees) { 620 // op + degrees 621 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar); 622 uint32_t initialOffset = this->addDraw(ROTATE, &size); 623 addScalar(degrees); 624 validate(initialOffset, size); 625 return this->INHERITED::rotate(degrees); 626 } 627 628 bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) { 629 // op + sx + sy 630 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 631 uint32_t initialOffset = this->addDraw(SKEW, &size); 632 addScalar(sx); 633 addScalar(sy); 634 validate(initialOffset, size); 635 return this->INHERITED::skew(sx, sy); 636 } 637 638 bool SkPictureRecord::concat(const SkMatrix& matrix) { 639 validate(fWriter.size(), 0); 640 // op + matrix index 641 uint32_t size = 2 * kUInt32Size; 642 uint32_t initialOffset = this->addDraw(CONCAT, &size); 643 addMatrix(matrix); 644 validate(initialOffset, size); 645 return this->INHERITED::concat(matrix); 646 } 647 648 void SkPictureRecord::setMatrix(const SkMatrix& matrix) { 649 validate(fWriter.size(), 0); 650 // op + matrix index 651 uint32_t size = 2 * kUInt32Size; 652 uint32_t initialOffset = this->addDraw(SET_MATRIX, &size); 653 addMatrix(matrix); 654 validate(initialOffset, size); 655 this->INHERITED::setMatrix(matrix); 656 } 657 658 static bool regionOpExpands(SkRegion::Op op) { 659 switch (op) { 660 case SkRegion::kUnion_Op: 661 case SkRegion::kXOR_Op: 662 case SkRegion::kReverseDifference_Op: 663 case SkRegion::kReplace_Op: 664 return true; 665 case SkRegion::kIntersect_Op: 666 case SkRegion::kDifference_Op: 667 return false; 668 default: 669 SkDEBUGFAIL("unknown region op"); 670 return false; 671 } 672 } 673 674 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { 675 int32_t offset = fRestoreOffsetStack.top(); 676 while (offset > 0) { 677 uint32_t* peek = fWriter.peek32(offset); 678 offset = *peek; 679 *peek = restoreOffset; 680 } 681 682 #ifdef SK_DEBUG 683 // assert that the final offset value points to a save verb 684 uint32_t opSize; 685 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); 686 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); 687 #endif 688 } 689 690 void SkPictureRecord::beginRecording() { 691 // we have to call this *after* our constructor, to ensure that it gets 692 // recorded. This is balanced by restoreToCount() call from endRecording, 693 // which in-turn calls our overridden restore(), so those get recorded too. 694 fInitialSaveCount = this->save(kMatrixClip_SaveFlag); 695 } 696 697 void SkPictureRecord::endRecording() { 698 SkASSERT(kNoInitialSave != fInitialSaveCount); 699 this->restoreToCount(fInitialSaveCount); 700 } 701 702 void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { 703 if (fRestoreOffsetStack.isEmpty()) { 704 return; 705 } 706 707 if (regionOpExpands(op)) { 708 // Run back through any previous clip ops, and mark their offset to 709 // be 0, disabling their ability to trigger a jump-to-restore, otherwise 710 // they could hide this clips ability to expand the clip (i.e. go from 711 // empty to non-empty). 712 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0); 713 } 714 715 size_t offset = fWriter.size(); 716 // The RestoreOffset field is initially filled with a placeholder 717 // value that points to the offset of the previous RestoreOffset 718 // in the current stack level, thus forming a linked list so that 719 // the restore offsets can be filled in when the corresponding 720 // restore command is recorded. 721 addInt(fRestoreOffsetStack.top()); 722 fRestoreOffsetStack.top() = offset; 723 } 724 725 bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 726 // id + rect + clip params 727 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; 728 // recordRestoreOffsetPlaceholder doesn't always write an offset 729 if (!fRestoreOffsetStack.isEmpty()) { 730 // + restore offset 731 size += kUInt32Size; 732 } 733 uint32_t initialOffset = this->addDraw(CLIP_RECT, &size); 734 addRect(rect); 735 addInt(ClipParams_pack(op, doAA)); 736 recordRestoreOffsetPlaceholder(op); 737 738 validate(initialOffset, size); 739 return this->INHERITED::clipRect(rect, op, doAA); 740 } 741 742 bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 743 if (rrect.isRect()) { 744 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA); 745 } 746 747 // op + rrect + clip params 748 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; 749 // recordRestoreOffsetPlaceholder doesn't always write an offset 750 if (!fRestoreOffsetStack.isEmpty()) { 751 // + restore offset 752 size += kUInt32Size; 753 } 754 uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size); 755 addRRect(rrect); 756 addInt(ClipParams_pack(op, doAA)); 757 recordRestoreOffsetPlaceholder(op); 758 759 validate(initialOffset, size); 760 761 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 762 return this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false); 763 } else { 764 return this->INHERITED::clipRRect(rrect, op, doAA); 765 } 766 } 767 768 bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 769 770 SkRect r; 771 if (!path.isInverseFillType() && path.isRect(&r)) { 772 return this->clipRect(r, op, doAA); 773 } 774 775 // op + path index + clip params 776 uint32_t size = 3 * kUInt32Size; 777 // recordRestoreOffsetPlaceholder doesn't always write an offset 778 if (!fRestoreOffsetStack.isEmpty()) { 779 // + restore offset 780 size += kUInt32Size; 781 } 782 uint32_t initialOffset = this->addDraw(CLIP_PATH, &size); 783 addPath(path); 784 addInt(ClipParams_pack(op, doAA)); 785 recordRestoreOffsetPlaceholder(op); 786 787 validate(initialOffset, size); 788 789 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 790 return this->updateClipConservativelyUsingBounds(path.getBounds(), op, 791 path.isInverseFillType()); 792 } else { 793 return this->INHERITED::clipPath(path, op, doAA); 794 } 795 } 796 797 bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { 798 // op + region index + clip params 799 uint32_t size = 3 * kUInt32Size; 800 // recordRestoreOffsetPlaceholder doesn't always write an offset 801 if (!fRestoreOffsetStack.isEmpty()) { 802 // + restore offset 803 size += kUInt32Size; 804 } 805 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size); 806 addRegion(region); 807 addInt(ClipParams_pack(op, false)); 808 recordRestoreOffsetPlaceholder(op); 809 810 validate(initialOffset, size); 811 return this->INHERITED::clipRegion(region, op); 812 } 813 814 void SkPictureRecord::clear(SkColor color) { 815 // op + color 816 uint32_t size = 2 * kUInt32Size; 817 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size); 818 addInt(color); 819 validate(initialOffset, size); 820 } 821 822 void SkPictureRecord::drawPaint(const SkPaint& paint) { 823 // op + paint index 824 uint32_t size = 2 * kUInt32Size; 825 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size); 826 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size()); 827 addPaint(paint); 828 validate(initialOffset, size); 829 } 830 831 void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 832 const SkPaint& paint) { 833 // op + paint index + mode + count + point data 834 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); 835 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size); 836 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size()); 837 addPaint(paint); 838 addInt(mode); 839 addInt(count); 840 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 841 validate(initialOffset, size); 842 } 843 844 void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { 845 // op + paint index + rect 846 uint32_t size = 2 * kUInt32Size + sizeof(oval); 847 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size); 848 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size()); 849 addPaint(paint); 850 addRect(oval); 851 validate(initialOffset, size); 852 } 853 854 void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { 855 // op + paint index + rect 856 uint32_t size = 2 * kUInt32Size + sizeof(rect); 857 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size); 858 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size()); 859 addPaint(paint); 860 addRect(rect); 861 validate(initialOffset, size); 862 } 863 864 void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 865 if (rrect.isRect()) { 866 this->SkPictureRecord::drawRect(rrect.getBounds(), paint); 867 } else if (rrect.isOval()) { 868 this->SkPictureRecord::drawOval(rrect.getBounds(), paint); 869 } else { 870 // op + paint index + rrect 871 uint32_t initialOffset, size; 872 size = 2 * kUInt32Size + SkRRect::kSizeInMemory; 873 initialOffset = this->addDraw(DRAW_RRECT, &size); 874 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size()); 875 addPaint(paint); 876 addRRect(rrect); 877 validate(initialOffset, size); 878 } 879 } 880 881 void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { 882 // op + paint index + path index 883 uint32_t size = 3 * kUInt32Size; 884 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size); 885 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size()); 886 addPaint(paint); 887 addPath(path); 888 validate(initialOffset, size); 889 } 890 891 void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 892 const SkPaint* paint = NULL) { 893 // op + paint index + bitmap index + left + top 894 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 895 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size); 896 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size()); 897 addPaintPtr(paint); 898 addBitmap(bitmap); 899 addScalar(left); 900 addScalar(top); 901 validate(initialOffset, size); 902 } 903 904 void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 905 const SkRect& dst, const SkPaint* paint) { 906 // id + paint index + bitmap index + bool for 'src' 907 uint32_t size = 4 * kUInt32Size; 908 if (NULL != src) { 909 size += sizeof(*src); // + rect 910 } 911 size += sizeof(dst); // + rect 912 913 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); 914 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size()); 915 addPaintPtr(paint); 916 addBitmap(bitmap); 917 addRectPtr(src); // may be null 918 addRect(dst); 919 validate(initialOffset, size); 920 } 921 922 void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 923 const SkPaint* paint) { 924 // id + paint index + bitmap index + matrix index 925 uint32_t size = 4 * kUInt32Size; 926 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); 927 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size()); 928 addPaintPtr(paint); 929 addBitmap(bitmap); 930 addMatrix(matrix); 931 validate(initialOffset, size); 932 } 933 934 void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 935 const SkRect& dst, const SkPaint* paint) { 936 // op + paint index + bitmap id + center + dst rect 937 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); 938 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); 939 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size()); 940 addPaintPtr(paint); 941 addBitmap(bitmap); 942 addIRect(center); 943 addRect(dst); 944 validate(initialOffset, size); 945 } 946 947 void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, 948 const SkPaint* paint = NULL) { 949 // op + paint index + bitmap index + left + top 950 uint32_t size = 5 * kUInt32Size; 951 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size); 952 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size()); 953 addPaintPtr(paint); 954 addBitmap(bitmap); 955 addInt(left); 956 addInt(top); 957 validate(initialOffset, size); 958 } 959 960 // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been 961 // tweaked by paint.computeFastBounds(). 962 // 963 static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) { 964 SkPaint::FontMetrics metrics; 965 paint.getFontMetrics(&metrics); 966 SkRect bounds; 967 // construct a rect so we can see any adjustments from the paint. 968 // we use 0,1 for left,right, just so the rect isn't empty 969 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); 970 (void)paint.computeFastBounds(bounds, &bounds); 971 topbot[0] = bounds.fTop; 972 topbot[1] = bounds.fBottom; 973 } 974 975 void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat, 976 SkScalar minY, SkScalar maxY) { 977 if (!flat.isTopBotWritten()) { 978 computeFontMetricsTopBottom(paint, flat.writableTopBot()); 979 SkASSERT(flat.isTopBotWritten()); 980 } 981 addScalar(flat.topBot()[0] + minY); 982 addScalar(flat.topBot()[1] + maxY); 983 } 984 985 void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, 986 SkScalar y, const SkPaint& paint) { 987 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 988 989 // op + paint index + length + 'length' worth of chars + x + y 990 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); 991 if (fast) { 992 size += 2 * sizeof(SkScalar); // + top & bottom 993 } 994 995 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; 996 uint32_t initialOffset = this->addDraw(op, &size); 997 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); 998 const SkFlatData* flatPaintData = addPaint(paint); 999 SkASSERT(flatPaintData); 1000 addText(text, byteLength); 1001 addScalar(x); 1002 addScalar(y); 1003 if (fast) { 1004 addFontMetricsTopBottom(paint, *flatPaintData, y, y); 1005 } 1006 validate(initialOffset, size); 1007 } 1008 1009 void SkPictureRecord::drawPosText(const void* text, size_t byteLength, 1010 const SkPoint pos[], const SkPaint& paint) { 1011 size_t points = paint.countText(text, byteLength); 1012 if (0 == points) 1013 return; 1014 1015 bool canUseDrawH = true; 1016 SkScalar minY = pos[0].fY; 1017 SkScalar maxY = pos[0].fY; 1018 // check if the caller really should have used drawPosTextH() 1019 { 1020 const SkScalar firstY = pos[0].fY; 1021 for (size_t index = 1; index < points; index++) { 1022 if (pos[index].fY != firstY) { 1023 canUseDrawH = false; 1024 if (pos[index].fY < minY) { 1025 minY = pos[index].fY; 1026 } else if (pos[index].fY > maxY) { 1027 maxY = pos[index].fY; 1028 } 1029 } 1030 } 1031 } 1032 1033 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds(); 1034 bool fast = canUseDrawH && fastBounds; 1035 1036 // op + paint index + length + 'length' worth of data + num points 1037 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1038 if (canUseDrawH) { 1039 if (fast) { 1040 size += 2 * sizeof(SkScalar); // + top & bottom 1041 } 1042 // + y-pos + actual x-point data 1043 size += sizeof(SkScalar) + points * sizeof(SkScalar); 1044 } else { 1045 // + x&y point data 1046 size += points * sizeof(SkPoint); 1047 if (fastBounds) { 1048 size += 2 * sizeof(SkScalar); // + top & bottom 1049 } 1050 } 1051 1052 DrawType op; 1053 if (fast) { 1054 op = DRAW_POS_TEXT_H_TOP_BOTTOM; 1055 } else if (canUseDrawH) { 1056 op = DRAW_POS_TEXT_H; 1057 } else if (fastBounds) { 1058 op = DRAW_POS_TEXT_TOP_BOTTOM; 1059 } else { 1060 op = DRAW_POS_TEXT; 1061 } 1062 uint32_t initialOffset = this->addDraw(op, &size); 1063 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); 1064 const SkFlatData* flatPaintData = addPaint(paint); 1065 SkASSERT(flatPaintData); 1066 addText(text, byteLength); 1067 addInt(points); 1068 1069 #ifdef SK_DEBUG_SIZE 1070 size_t start = fWriter.size(); 1071 #endif 1072 if (canUseDrawH) { 1073 if (fast) { 1074 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY); 1075 } 1076 addScalar(pos[0].fY); 1077 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); 1078 for (size_t index = 0; index < points; index++) 1079 *xptr++ = pos[index].fX; 1080 } else { 1081 fWriter.writeMul4(pos, points * sizeof(SkPoint)); 1082 if (fastBounds) { 1083 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); 1084 } 1085 } 1086 #ifdef SK_DEBUG_SIZE 1087 fPointBytes += fWriter.size() - start; 1088 fPointWrites += points; 1089 #endif 1090 validate(initialOffset, size); 1091 } 1092 1093 void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength, 1094 const SkScalar xpos[], SkScalar constY, 1095 const SkPaint& paint) { 1096 size_t points = paint.countText(text, byteLength); 1097 if (0 == points) 1098 return; 1099 1100 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 1101 1102 // op + paint index + length + 'length' worth of data + num points 1103 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1104 if (fast) { 1105 size += 2 * sizeof(SkScalar); // + top & bottom 1106 } 1107 // + y + the actual points 1108 size += 1 * kUInt32Size + points * sizeof(SkScalar); 1109 1110 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, 1111 &size); 1112 const SkFlatData* flatPaintData = addPaint(paint); 1113 SkASSERT(flatPaintData); 1114 addText(text, byteLength); 1115 addInt(points); 1116 1117 #ifdef SK_DEBUG_SIZE 1118 size_t start = fWriter.size(); 1119 #endif 1120 if (fast) { 1121 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); 1122 } 1123 addScalar(constY); 1124 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); 1125 #ifdef SK_DEBUG_SIZE 1126 fPointBytes += fWriter.size() - start; 1127 fPointWrites += points; 1128 #endif 1129 validate(initialOffset, size); 1130 } 1131 1132 void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, 1133 const SkPath& path, const SkMatrix* matrix, 1134 const SkPaint& paint) { 1135 // op + paint index + length + 'length' worth of data + path index + matrix index 1136 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size; 1137 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); 1138 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size()); 1139 addPaint(paint); 1140 addText(text, byteLength); 1141 addPath(path); 1142 addMatrixPtr(matrix); 1143 validate(initialOffset, size); 1144 } 1145 1146 void SkPictureRecord::drawPicture(SkPicture& picture) { 1147 // op + picture index 1148 uint32_t size = 2 * kUInt32Size; 1149 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size); 1150 addPicture(picture); 1151 validate(initialOffset, size); 1152 } 1153 1154 void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, 1155 const SkPoint vertices[], const SkPoint texs[], 1156 const SkColor colors[], SkXfermode*, 1157 const uint16_t indices[], int indexCount, 1158 const SkPaint& paint) { 1159 uint32_t flags = 0; 1160 if (texs) { 1161 flags |= DRAW_VERTICES_HAS_TEXS; 1162 } 1163 if (colors) { 1164 flags |= DRAW_VERTICES_HAS_COLORS; 1165 } 1166 if (indexCount > 0) { 1167 flags |= DRAW_VERTICES_HAS_INDICES; 1168 } 1169 1170 // op + paint index + flags + vmode + vCount + vertices 1171 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); 1172 if (flags & DRAW_VERTICES_HAS_TEXS) { 1173 size += vertexCount * sizeof(SkPoint); // + uvs 1174 } 1175 if (flags & DRAW_VERTICES_HAS_COLORS) { 1176 size += vertexCount * sizeof(SkColor); // + vert colors 1177 } 1178 if (flags & DRAW_VERTICES_HAS_INDICES) { 1179 // + num indices + indices 1180 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); 1181 } 1182 1183 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size); 1184 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size()); 1185 addPaint(paint); 1186 addInt(flags); 1187 addInt(vmode); 1188 addInt(vertexCount); 1189 addPoints(vertices, vertexCount); 1190 if (flags & DRAW_VERTICES_HAS_TEXS) { 1191 addPoints(texs, vertexCount); 1192 } 1193 if (flags & DRAW_VERTICES_HAS_COLORS) { 1194 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); 1195 } 1196 if (flags & DRAW_VERTICES_HAS_INDICES) { 1197 addInt(indexCount); 1198 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); 1199 } 1200 validate(initialOffset, size); 1201 } 1202 1203 void SkPictureRecord::drawData(const void* data, size_t length) { 1204 // op + length + 'length' worth of data 1205 uint32_t size = 2 * kUInt32Size + SkAlign4(length); 1206 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size); 1207 addInt(length); 1208 fWriter.writePad(data, length); 1209 validate(initialOffset, size); 1210 } 1211 1212 void SkPictureRecord::beginCommentGroup(const char* description) { 1213 // op/size + length of string + \0 terminated chars 1214 int length = strlen(description); 1215 uint32_t size = 2 * kUInt32Size + SkAlign4(length + 1); 1216 uint32_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size); 1217 fWriter.writeString(description, length); 1218 validate(initialOffset, size); 1219 } 1220 1221 void SkPictureRecord::addComment(const char* kywd, const char* value) { 1222 // op/size + 2x length of string + 2x \0 terminated chars 1223 int kywdLen = strlen(kywd); 1224 int valueLen = strlen(value); 1225 uint32_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1); 1226 uint32_t initialOffset = this->addDraw(COMMENT, &size); 1227 fWriter.writeString(kywd, kywdLen); 1228 fWriter.writeString(value, valueLen); 1229 validate(initialOffset, size); 1230 } 1231 1232 void SkPictureRecord::endCommentGroup() { 1233 // op/size 1234 uint32_t size = 1 * kUInt32Size; 1235 uint32_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size); 1236 validate(initialOffset, size); 1237 } 1238 1239 /////////////////////////////////////////////////////////////////////////////// 1240 1241 void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { 1242 const int index = fBitmapHeap->insert(bitmap); 1243 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In 1244 // release builds, the invalid value will be recorded so that the reader will know that there 1245 // was a problem. 1246 SkASSERT(index != SkBitmapHeap::INVALID_SLOT); 1247 addInt(index); 1248 } 1249 1250 void SkPictureRecord::addMatrix(const SkMatrix& matrix) { 1251 addMatrixPtr(&matrix); 1252 } 1253 1254 void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) { 1255 this->addInt(matrix ? fMatrices.find(*matrix) : 0); 1256 } 1257 1258 const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { 1259 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL; 1260 int index = data ? data->index() : 0; 1261 this->addInt(index); 1262 return data; 1263 } 1264 1265 void SkPictureRecord::addPath(const SkPath& path) { 1266 if (NULL == fPathHeap) { 1267 fPathHeap = SkNEW(SkPathHeap); 1268 } 1269 addInt(fPathHeap->append(path)); 1270 } 1271 1272 void SkPictureRecord::addPicture(SkPicture& picture) { 1273 int index = fPictureRefs.find(&picture); 1274 if (index < 0) { // not found 1275 index = fPictureRefs.count(); 1276 *fPictureRefs.append() = &picture; 1277 picture.ref(); 1278 } 1279 // follow the convention of recording a 1-based index 1280 addInt(index + 1); 1281 } 1282 1283 void SkPictureRecord::addPoint(const SkPoint& point) { 1284 #ifdef SK_DEBUG_SIZE 1285 size_t start = fWriter.size(); 1286 #endif 1287 fWriter.writePoint(point); 1288 #ifdef SK_DEBUG_SIZE 1289 fPointBytes += fWriter.size() - start; 1290 fPointWrites++; 1291 #endif 1292 } 1293 1294 void SkPictureRecord::addPoints(const SkPoint pts[], int count) { 1295 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 1296 #ifdef SK_DEBUG_SIZE 1297 fPointBytes += count * sizeof(SkPoint); 1298 fPointWrites++; 1299 #endif 1300 } 1301 1302 void SkPictureRecord::addRect(const SkRect& rect) { 1303 #ifdef SK_DEBUG_SIZE 1304 size_t start = fWriter.size(); 1305 #endif 1306 fWriter.writeRect(rect); 1307 #ifdef SK_DEBUG_SIZE 1308 fRectBytes += fWriter.size() - start; 1309 fRectWrites++; 1310 #endif 1311 } 1312 1313 void SkPictureRecord::addRectPtr(const SkRect* rect) { 1314 if (fWriter.writeBool(rect != NULL)) { 1315 fWriter.writeRect(*rect); 1316 } 1317 } 1318 1319 void SkPictureRecord::addIRect(const SkIRect& rect) { 1320 fWriter.write(&rect, sizeof(rect)); 1321 } 1322 1323 void SkPictureRecord::addIRectPtr(const SkIRect* rect) { 1324 if (fWriter.writeBool(rect != NULL)) { 1325 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; 1326 } 1327 } 1328 1329 void SkPictureRecord::addRRect(const SkRRect& rrect) { 1330 fWriter.writeRRect(rrect); 1331 } 1332 1333 void SkPictureRecord::addRegion(const SkRegion& region) { 1334 addInt(fRegions.find(region)); 1335 } 1336 1337 void SkPictureRecord::addText(const void* text, size_t byteLength) { 1338 #ifdef SK_DEBUG_SIZE 1339 size_t start = fWriter.size(); 1340 #endif 1341 addInt(byteLength); 1342 fWriter.writePad(text, byteLength); 1343 #ifdef SK_DEBUG_SIZE 1344 fTextBytes += fWriter.size() - start; 1345 fTextWrites++; 1346 #endif 1347 } 1348 1349 /////////////////////////////////////////////////////////////////////////////// 1350 1351 #ifdef SK_DEBUG_SIZE 1352 size_t SkPictureRecord::size() const { 1353 size_t result = 0; 1354 size_t sizeData; 1355 bitmaps(&sizeData); 1356 result += sizeData; 1357 matrices(&sizeData); 1358 result += sizeData; 1359 paints(&sizeData); 1360 result += sizeData; 1361 paths(&sizeData); 1362 result += sizeData; 1363 pictures(&sizeData); 1364 result += sizeData; 1365 regions(&sizeData); 1366 result += sizeData; 1367 result += streamlen(); 1368 return result; 1369 } 1370 1371 int SkPictureRecord::bitmaps(size_t* size) const { 1372 size_t result = 0; 1373 int count = fBitmaps.count(); 1374 for (int index = 0; index < count; index++) 1375 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size(); 1376 *size = result; 1377 return count; 1378 } 1379 1380 int SkPictureRecord::matrices(size_t* size) const { 1381 int count = fMatrices.count(); 1382 *size = sizeof(fMatrices[0]) * count; 1383 return count; 1384 } 1385 1386 int SkPictureRecord::paints(size_t* size) const { 1387 size_t result = 0; 1388 int count = fPaints.count(); 1389 for (int index = 0; index < count; index++) 1390 result += sizeof(fPaints[index]) + fPaints[index]->size(); 1391 *size = result; 1392 return count; 1393 } 1394 1395 int SkPictureRecord::paths(size_t* size) const { 1396 size_t result = 0; 1397 int count = fPaths.count(); 1398 for (int index = 0; index < count; index++) 1399 result += sizeof(fPaths[index]) + fPaths[index]->size(); 1400 *size = result; 1401 return count; 1402 } 1403 1404 int SkPictureRecord::regions(size_t* size) const { 1405 size_t result = 0; 1406 int count = fRegions.count(); 1407 for (int index = 0; index < count; index++) 1408 result += sizeof(fRegions[index]) + fRegions[index]->size(); 1409 *size = result; 1410 return count; 1411 } 1412 1413 size_t SkPictureRecord::streamlen() const { 1414 return fWriter.size(); 1415 } 1416 #endif 1417 1418 #ifdef SK_DEBUG_VALIDATE 1419 void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const { 1420 SkASSERT(fWriter.size() == initialOffset + size); 1421 1422 validateBitmaps(); 1423 validateMatrices(); 1424 validatePaints(); 1425 validatePaths(); 1426 validateRegions(); 1427 } 1428 1429 void SkPictureRecord::validateBitmaps() const { 1430 int count = fBitmapHeap->count(); 1431 SkASSERT((unsigned) count < 0x1000); 1432 for (int index = 0; index < count; index++) { 1433 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index); 1434 SkASSERT(bitPtr); 1435 bitPtr->validate(); 1436 } 1437 } 1438 1439 void SkPictureRecord::validateMatrices() const { 1440 int count = fMatrices.count(); 1441 SkASSERT((unsigned) count < 0x1000); 1442 for (int index = 0; index < count; index++) { 1443 const SkFlatData* matrix = fMatrices[index]; 1444 SkASSERT(matrix); 1445 // matrix->validate(); 1446 } 1447 } 1448 1449 void SkPictureRecord::validatePaints() const { 1450 int count = fPaints.count(); 1451 SkASSERT((unsigned) count < 0x1000); 1452 for (int index = 0; index < count; index++) { 1453 const SkFlatData* paint = fPaints[index]; 1454 SkASSERT(paint); 1455 // paint->validate(); 1456 } 1457 } 1458 1459 void SkPictureRecord::validatePaths() const { 1460 if (NULL == fPathHeap) { 1461 return; 1462 } 1463 1464 int count = fPathHeap->count(); 1465 SkASSERT((unsigned) count < 0x1000); 1466 for (int index = 0; index < count; index++) { 1467 const SkPath& path = (*fPathHeap)[index]; 1468 path.validate(); 1469 } 1470 } 1471 1472 void SkPictureRecord::validateRegions() const { 1473 int count = fRegions.count(); 1474 SkASSERT((unsigned) count < 0x1000); 1475 for (int index = 0; index < count; index++) { 1476 const SkFlatData* region = fRegions[index]; 1477 SkASSERT(region); 1478 // region->validate(); 1479 } 1480 } 1481 #endif 1482