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