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