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