SkPictureRecord.cpp revision 4bb50b22fce5c4031549976cf7b04d63cc22e624
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 return this->INHERITED::clipRect(path.getBounds(), op, doAA); 787 } else { 788 return this->INHERITED::clipPath(path, op, doAA); 789 } 790} 791 792bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { 793 // op + region index + clip params 794 uint32_t size = 3 * kUInt32Size; 795 // recordRestoreOffsetPlaceholder doesn't always write an offset 796 if (!fRestoreOffsetStack.isEmpty()) { 797 // + restore offset 798 size += kUInt32Size; 799 } 800 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size); 801 addRegion(region); 802 addInt(ClipParams_pack(op, false)); 803 recordRestoreOffsetPlaceholder(op); 804 805 validate(initialOffset, size); 806 return this->INHERITED::clipRegion(region, op); 807} 808 809void SkPictureRecord::clear(SkColor color) { 810 // op + color 811 uint32_t size = 2 * kUInt32Size; 812 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size); 813 addInt(color); 814 validate(initialOffset, size); 815} 816 817void SkPictureRecord::drawPaint(const SkPaint& paint) { 818 // op + paint index 819 uint32_t size = 2 * kUInt32Size; 820 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size); 821 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size()); 822 addPaint(paint); 823 validate(initialOffset, size); 824} 825 826void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 827 const SkPaint& paint) { 828 // op + paint index + mode + count + point data 829 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); 830 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size); 831 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size()); 832 addPaint(paint); 833 addInt(mode); 834 addInt(count); 835 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 836 validate(initialOffset, size); 837} 838 839void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { 840 // op + paint index + rect 841 uint32_t size = 2 * kUInt32Size + sizeof(oval); 842 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size); 843 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size()); 844 addPaint(paint); 845 addRect(oval); 846 validate(initialOffset, size); 847} 848 849void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { 850 // op + paint index + rect 851 uint32_t size = 2 * kUInt32Size + sizeof(rect); 852 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size); 853 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size()); 854 addPaint(paint); 855 addRect(rect); 856 validate(initialOffset, size); 857} 858 859void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 860 uint32_t initialOffset, size; 861 if (rrect.isRect()) { 862 // op + paint index + rect 863 size = 2 * kUInt32Size + sizeof(SkRect); 864 initialOffset = this->addDraw(DRAW_RECT, &size); 865 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size()); 866 addPaint(paint); 867 addRect(rrect.getBounds()); 868 } else if (rrect.isOval()) { 869 // op + paint index + rect 870 size = 2 * kUInt32Size + sizeof(SkRect); 871 initialOffset = this->addDraw(DRAW_OVAL, &size); 872 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size()); 873 addPaint(paint); 874 addRect(rrect.getBounds()); 875 } else { 876 // op + paint index + rrect 877 size = 2 * kUInt32Size + SkRRect::kSizeInMemory; 878 initialOffset = this->addDraw(DRAW_RRECT, &size); 879 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size()); 880 addPaint(paint); 881 addRRect(rrect); 882 } 883 validate(initialOffset, size); 884} 885 886void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { 887 // op + paint index + path index 888 uint32_t size = 3 * kUInt32Size; 889 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size); 890 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size()); 891 addPaint(paint); 892 addPath(path); 893 validate(initialOffset, size); 894} 895 896void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 897 const SkPaint* paint = NULL) { 898 // op + paint index + bitmap index + left + top 899 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 900 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size); 901 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size()); 902 addPaintPtr(paint); 903 addBitmap(bitmap); 904 addScalar(left); 905 addScalar(top); 906 validate(initialOffset, size); 907} 908 909void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 910 const SkRect& dst, const SkPaint* paint) { 911 // id + paint index + bitmap index + bool for 'src' 912 uint32_t size = 4 * kUInt32Size; 913 if (NULL != src) { 914 size += sizeof(*src); // + rect 915 } 916 size += sizeof(dst); // + rect 917 918 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); 919 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size()); 920 addPaintPtr(paint); 921 addBitmap(bitmap); 922 addRectPtr(src); // may be null 923 addRect(dst); 924 validate(initialOffset, size); 925} 926 927void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 928 const SkPaint* paint) { 929 // id + paint index + bitmap index + matrix index 930 uint32_t size = 4 * kUInt32Size; 931 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); 932 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size()); 933 addPaintPtr(paint); 934 addBitmap(bitmap); 935 addMatrix(matrix); 936 validate(initialOffset, size); 937} 938 939void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 940 const SkRect& dst, const SkPaint* paint) { 941 // op + paint index + bitmap id + center + dst rect 942 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); 943 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); 944 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size()); 945 addPaintPtr(paint); 946 addBitmap(bitmap); 947 addIRect(center); 948 addRect(dst); 949 validate(initialOffset, size); 950} 951 952void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, 953 const SkPaint* paint = NULL) { 954 // op + paint index + bitmap index + left + top 955 uint32_t size = 5 * kUInt32Size; 956 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size); 957 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size()); 958 addPaintPtr(paint); 959 addBitmap(bitmap); 960 addInt(left); 961 addInt(top); 962 validate(initialOffset, size); 963} 964 965// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been 966// tweaked by paint.computeFastBounds(). 967// 968static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) { 969 SkPaint::FontMetrics metrics; 970 paint.getFontMetrics(&metrics); 971 SkRect bounds; 972 // construct a rect so we can see any adjustments from the paint. 973 // we use 0,1 for left,right, just so the rect isn't empty 974 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); 975 (void)paint.computeFastBounds(bounds, &bounds); 976 topbot[0] = bounds.fTop; 977 topbot[1] = bounds.fBottom; 978} 979 980void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat, 981 SkScalar minY, SkScalar maxY) { 982 if (!flat.isTopBotWritten()) { 983 computeFontMetricsTopBottom(paint, flat.writableTopBot()); 984 SkASSERT(flat.isTopBotWritten()); 985 } 986 addScalar(flat.topBot()[0] + minY); 987 addScalar(flat.topBot()[1] + maxY); 988} 989 990void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, 991 SkScalar y, const SkPaint& paint) { 992 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 993 994 // op + paint index + length + 'length' worth of chars + x + y 995 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); 996 if (fast) { 997 size += 2 * sizeof(SkScalar); // + top & bottom 998 } 999 1000 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; 1001 uint32_t initialOffset = this->addDraw(op, &size); 1002 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); 1003 const SkFlatData* flatPaintData = addPaint(paint); 1004 SkASSERT(flatPaintData); 1005 addText(text, byteLength); 1006 addScalar(x); 1007 addScalar(y); 1008 if (fast) { 1009 addFontMetricsTopBottom(paint, *flatPaintData, y, y); 1010 } 1011 validate(initialOffset, size); 1012} 1013 1014void SkPictureRecord::drawPosText(const void* text, size_t byteLength, 1015 const SkPoint pos[], const SkPaint& paint) { 1016 size_t points = paint.countText(text, byteLength); 1017 if (0 == points) 1018 return; 1019 1020 bool canUseDrawH = true; 1021 SkScalar minY = pos[0].fY; 1022 SkScalar maxY = pos[0].fY; 1023 // check if the caller really should have used drawPosTextH() 1024 { 1025 const SkScalar firstY = pos[0].fY; 1026 for (size_t index = 1; index < points; index++) { 1027 if (pos[index].fY != firstY) { 1028 canUseDrawH = false; 1029 if (pos[index].fY < minY) { 1030 minY = pos[index].fY; 1031 } else if (pos[index].fY > maxY) { 1032 maxY = pos[index].fY; 1033 } 1034 } 1035 } 1036 } 1037 1038 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds(); 1039 bool fast = canUseDrawH && fastBounds; 1040 1041 // op + paint index + length + 'length' worth of data + num points 1042 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1043 if (canUseDrawH) { 1044 if (fast) { 1045 size += 2 * sizeof(SkScalar); // + top & bottom 1046 } 1047 // + y-pos + actual x-point data 1048 size += sizeof(SkScalar) + points * sizeof(SkScalar); 1049 } else { 1050 // + x&y point data 1051 size += points * sizeof(SkPoint); 1052 if (fastBounds) { 1053 size += 2 * sizeof(SkScalar); // + top & bottom 1054 } 1055 } 1056 1057 DrawType op; 1058 if (fast) { 1059 op = DRAW_POS_TEXT_H_TOP_BOTTOM; 1060 } else if (canUseDrawH) { 1061 op = DRAW_POS_TEXT_H; 1062 } else if (fastBounds) { 1063 op = DRAW_POS_TEXT_TOP_BOTTOM; 1064 } else { 1065 op = DRAW_POS_TEXT; 1066 } 1067 uint32_t initialOffset = this->addDraw(op, &size); 1068 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); 1069 const SkFlatData* flatPaintData = addPaint(paint); 1070 SkASSERT(flatPaintData); 1071 addText(text, byteLength); 1072 addInt(points); 1073 1074#ifdef SK_DEBUG_SIZE 1075 size_t start = fWriter.size(); 1076#endif 1077 if (canUseDrawH) { 1078 if (fast) { 1079 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY); 1080 } 1081 addScalar(pos[0].fY); 1082 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); 1083 for (size_t index = 0; index < points; index++) 1084 *xptr++ = pos[index].fX; 1085 } else { 1086 fWriter.writeMul4(pos, points * sizeof(SkPoint)); 1087 if (fastBounds) { 1088 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); 1089 } 1090 } 1091#ifdef SK_DEBUG_SIZE 1092 fPointBytes += fWriter.size() - start; 1093 fPointWrites += points; 1094#endif 1095 validate(initialOffset, size); 1096} 1097 1098void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength, 1099 const SkScalar xpos[], SkScalar constY, 1100 const SkPaint& paint) { 1101 size_t points = paint.countText(text, byteLength); 1102 if (0 == points) 1103 return; 1104 1105 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 1106 1107 // op + paint index + length + 'length' worth of data + num points 1108 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1109 if (fast) { 1110 size += 2 * sizeof(SkScalar); // + top & bottom 1111 } 1112 // + y + the actual points 1113 size += 1 * kUInt32Size + points * sizeof(SkScalar); 1114 1115 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, 1116 &size); 1117 const SkFlatData* flatPaintData = addPaint(paint); 1118 SkASSERT(flatPaintData); 1119 addText(text, byteLength); 1120 addInt(points); 1121 1122#ifdef SK_DEBUG_SIZE 1123 size_t start = fWriter.size(); 1124#endif 1125 if (fast) { 1126 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); 1127 } 1128 addScalar(constY); 1129 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); 1130#ifdef SK_DEBUG_SIZE 1131 fPointBytes += fWriter.size() - start; 1132 fPointWrites += points; 1133#endif 1134 validate(initialOffset, size); 1135} 1136 1137void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, 1138 const SkPath& path, const SkMatrix* matrix, 1139 const SkPaint& paint) { 1140 // op + paint index + length + 'length' worth of data + path index + matrix index 1141 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size; 1142 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); 1143 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size()); 1144 addPaint(paint); 1145 addText(text, byteLength); 1146 addPath(path); 1147 addMatrixPtr(matrix); 1148 validate(initialOffset, size); 1149} 1150 1151void SkPictureRecord::drawPicture(SkPicture& picture) { 1152 // op + picture index 1153 uint32_t size = 2 * kUInt32Size; 1154 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size); 1155 addPicture(picture); 1156 validate(initialOffset, size); 1157} 1158 1159void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, 1160 const SkPoint vertices[], const SkPoint texs[], 1161 const SkColor colors[], SkXfermode*, 1162 const uint16_t indices[], int indexCount, 1163 const SkPaint& paint) { 1164 uint32_t flags = 0; 1165 if (texs) { 1166 flags |= DRAW_VERTICES_HAS_TEXS; 1167 } 1168 if (colors) { 1169 flags |= DRAW_VERTICES_HAS_COLORS; 1170 } 1171 if (indexCount > 0) { 1172 flags |= DRAW_VERTICES_HAS_INDICES; 1173 } 1174 1175 // op + paint index + flags + vmode + vCount + vertices 1176 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); 1177 if (flags & DRAW_VERTICES_HAS_TEXS) { 1178 size += vertexCount * sizeof(SkPoint); // + uvs 1179 } 1180 if (flags & DRAW_VERTICES_HAS_COLORS) { 1181 size += vertexCount * sizeof(SkColor); // + vert colors 1182 } 1183 if (flags & DRAW_VERTICES_HAS_INDICES) { 1184 // + num indices + indices 1185 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); 1186 } 1187 1188 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size); 1189 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size()); 1190 addPaint(paint); 1191 addInt(flags); 1192 addInt(vmode); 1193 addInt(vertexCount); 1194 addPoints(vertices, vertexCount); 1195 if (flags & DRAW_VERTICES_HAS_TEXS) { 1196 addPoints(texs, vertexCount); 1197 } 1198 if (flags & DRAW_VERTICES_HAS_COLORS) { 1199 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); 1200 } 1201 if (flags & DRAW_VERTICES_HAS_INDICES) { 1202 addInt(indexCount); 1203 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); 1204 } 1205 validate(initialOffset, size); 1206} 1207 1208void SkPictureRecord::drawData(const void* data, size_t length) { 1209 // op + length + 'length' worth of data 1210 uint32_t size = 2 * kUInt32Size + SkAlign4(length); 1211 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size); 1212 addInt(length); 1213 fWriter.writePad(data, length); 1214 validate(initialOffset, size); 1215} 1216 1217/////////////////////////////////////////////////////////////////////////////// 1218 1219void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { 1220 const int index = fBitmapHeap->insert(bitmap); 1221 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In 1222 // release builds, the invalid value will be recorded so that the reader will know that there 1223 // was a problem. 1224 SkASSERT(index != SkBitmapHeap::INVALID_SLOT); 1225 addInt(index); 1226} 1227 1228void SkPictureRecord::addMatrix(const SkMatrix& matrix) { 1229 addMatrixPtr(&matrix); 1230} 1231 1232void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) { 1233 this->addInt(matrix ? fMatrices.find(*matrix) : 0); 1234} 1235 1236const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { 1237 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL; 1238 int index = data ? data->index() : 0; 1239 this->addInt(index); 1240 return data; 1241} 1242 1243void SkPictureRecord::addPath(const SkPath& path) { 1244 if (NULL == fPathHeap) { 1245 fPathHeap = SkNEW(SkPathHeap); 1246 } 1247 addInt(fPathHeap->append(path)); 1248} 1249 1250void SkPictureRecord::addPicture(SkPicture& picture) { 1251 int index = fPictureRefs.find(&picture); 1252 if (index < 0) { // not found 1253 index = fPictureRefs.count(); 1254 *fPictureRefs.append() = &picture; 1255 picture.ref(); 1256 } 1257 // follow the convention of recording a 1-based index 1258 addInt(index + 1); 1259} 1260 1261void SkPictureRecord::addPoint(const SkPoint& point) { 1262#ifdef SK_DEBUG_SIZE 1263 size_t start = fWriter.size(); 1264#endif 1265 fWriter.writePoint(point); 1266#ifdef SK_DEBUG_SIZE 1267 fPointBytes += fWriter.size() - start; 1268 fPointWrites++; 1269#endif 1270} 1271 1272void SkPictureRecord::addPoints(const SkPoint pts[], int count) { 1273 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 1274#ifdef SK_DEBUG_SIZE 1275 fPointBytes += count * sizeof(SkPoint); 1276 fPointWrites++; 1277#endif 1278} 1279 1280void SkPictureRecord::addRect(const SkRect& rect) { 1281#ifdef SK_DEBUG_SIZE 1282 size_t start = fWriter.size(); 1283#endif 1284 fWriter.writeRect(rect); 1285#ifdef SK_DEBUG_SIZE 1286 fRectBytes += fWriter.size() - start; 1287 fRectWrites++; 1288#endif 1289} 1290 1291void SkPictureRecord::addRectPtr(const SkRect* rect) { 1292 if (fWriter.writeBool(rect != NULL)) { 1293 fWriter.writeRect(*rect); 1294 } 1295} 1296 1297void SkPictureRecord::addIRect(const SkIRect& rect) { 1298 fWriter.write(&rect, sizeof(rect)); 1299} 1300 1301void SkPictureRecord::addIRectPtr(const SkIRect* rect) { 1302 if (fWriter.writeBool(rect != NULL)) { 1303 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; 1304 } 1305} 1306 1307void SkPictureRecord::addRRect(const SkRRect& rrect) { 1308 fWriter.writeRRect(rrect); 1309} 1310 1311void SkPictureRecord::addRegion(const SkRegion& region) { 1312 addInt(fRegions.find(region)); 1313} 1314 1315void SkPictureRecord::addText(const void* text, size_t byteLength) { 1316#ifdef SK_DEBUG_SIZE 1317 size_t start = fWriter.size(); 1318#endif 1319 addInt(byteLength); 1320 fWriter.writePad(text, byteLength); 1321#ifdef SK_DEBUG_SIZE 1322 fTextBytes += fWriter.size() - start; 1323 fTextWrites++; 1324#endif 1325} 1326 1327/////////////////////////////////////////////////////////////////////////////// 1328 1329#ifdef SK_DEBUG_SIZE 1330size_t SkPictureRecord::size() const { 1331 size_t result = 0; 1332 size_t sizeData; 1333 bitmaps(&sizeData); 1334 result += sizeData; 1335 matrices(&sizeData); 1336 result += sizeData; 1337 paints(&sizeData); 1338 result += sizeData; 1339 paths(&sizeData); 1340 result += sizeData; 1341 pictures(&sizeData); 1342 result += sizeData; 1343 regions(&sizeData); 1344 result += sizeData; 1345 result += streamlen(); 1346 return result; 1347} 1348 1349int SkPictureRecord::bitmaps(size_t* size) const { 1350 size_t result = 0; 1351 int count = fBitmaps.count(); 1352 for (int index = 0; index < count; index++) 1353 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size(); 1354 *size = result; 1355 return count; 1356} 1357 1358int SkPictureRecord::matrices(size_t* size) const { 1359 int count = fMatrices.count(); 1360 *size = sizeof(fMatrices[0]) * count; 1361 return count; 1362} 1363 1364int SkPictureRecord::paints(size_t* size) const { 1365 size_t result = 0; 1366 int count = fPaints.count(); 1367 for (int index = 0; index < count; index++) 1368 result += sizeof(fPaints[index]) + fPaints[index]->size(); 1369 *size = result; 1370 return count; 1371} 1372 1373int SkPictureRecord::paths(size_t* size) const { 1374 size_t result = 0; 1375 int count = fPaths.count(); 1376 for (int index = 0; index < count; index++) 1377 result += sizeof(fPaths[index]) + fPaths[index]->size(); 1378 *size = result; 1379 return count; 1380} 1381 1382int SkPictureRecord::regions(size_t* size) const { 1383 size_t result = 0; 1384 int count = fRegions.count(); 1385 for (int index = 0; index < count; index++) 1386 result += sizeof(fRegions[index]) + fRegions[index]->size(); 1387 *size = result; 1388 return count; 1389} 1390 1391size_t SkPictureRecord::streamlen() const { 1392 return fWriter.size(); 1393} 1394#endif 1395 1396#ifdef SK_DEBUG_VALIDATE 1397void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const { 1398 SkASSERT(fWriter.size() == initialOffset + size); 1399 1400 validateBitmaps(); 1401 validateMatrices(); 1402 validatePaints(); 1403 validatePaths(); 1404 validateRegions(); 1405} 1406 1407void SkPictureRecord::validateBitmaps() const { 1408 int count = fBitmapHeap->count(); 1409 SkASSERT((unsigned) count < 0x1000); 1410 for (int index = 0; index < count; index++) { 1411 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index); 1412 SkASSERT(bitPtr); 1413 bitPtr->validate(); 1414 } 1415} 1416 1417void SkPictureRecord::validateMatrices() const { 1418 int count = fMatrices.count(); 1419 SkASSERT((unsigned) count < 0x1000); 1420 for (int index = 0; index < count; index++) { 1421 const SkFlatData* matrix = fMatrices[index]; 1422 SkASSERT(matrix); 1423// matrix->validate(); 1424 } 1425} 1426 1427void SkPictureRecord::validatePaints() const { 1428 int count = fPaints.count(); 1429 SkASSERT((unsigned) count < 0x1000); 1430 for (int index = 0; index < count; index++) { 1431 const SkFlatData* paint = fPaints[index]; 1432 SkASSERT(paint); 1433// paint->validate(); 1434 } 1435} 1436 1437void SkPictureRecord::validatePaths() const { 1438 if (NULL == fPathHeap) { 1439 return; 1440 } 1441 1442 int count = fPathHeap->count(); 1443 SkASSERT((unsigned) count < 0x1000); 1444 for (int index = 0; index < count; index++) { 1445 const SkPath& path = (*fPathHeap)[index]; 1446 path.validate(); 1447 } 1448} 1449 1450void SkPictureRecord::validateRegions() const { 1451 int count = fRegions.count(); 1452 SkASSERT((unsigned) count < 0x1000); 1453 for (int index = 0; index < count; index++) { 1454 const SkFlatData* region = fRegions[index]; 1455 SkASSERT(region); 1456// region->validate(); 1457 } 1458} 1459#endif 1460