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