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