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