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