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