SkPictureRecord.cpp revision 35e15633805081c8978c18910cb25ed53f06f6c2
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 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; 568 for (opt = 0; opt < SK_ARRAY_COUNT(gPictureRecordOpts); ++opt) { 569 if ((*gPictureRecordOpts[opt].fProc)(&fWriter, fRestoreOffsetStack.top(), &fPaints)) { 570 // Some optimization fired so don't add the RESTORE 571 size = 0; 572 initialOffset = fWriter.size(); 573 apply_optimization_to_bbh(gPictureRecordOpts[opt].fType, 574 fStateTree, fBoundingHierarchy); 575 break; 576 } 577 } 578 579 if (SK_ARRAY_COUNT(gPictureRecordOpts) == opt) { 580 // No optimization fired so add the RESTORE 581 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size()); 582 size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code 583 initialOffset = this->addDraw(RESTORE, &size); 584 } 585 586 fRestoreOffsetStack.pop(); 587 588 validate(initialOffset, size); 589 return this->INHERITED::restore(); 590} 591 592bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) { 593 // op + dx + dy 594 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 595 uint32_t initialOffset = this->addDraw(TRANSLATE, &size); 596 addScalar(dx); 597 addScalar(dy); 598 validate(initialOffset, size); 599 return this->INHERITED::translate(dx, dy); 600} 601 602bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) { 603 // op + sx + sy 604 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 605 uint32_t initialOffset = this->addDraw(SCALE, &size); 606 addScalar(sx); 607 addScalar(sy); 608 validate(initialOffset, size); 609 return this->INHERITED::scale(sx, sy); 610} 611 612bool SkPictureRecord::rotate(SkScalar degrees) { 613 // op + degrees 614 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar); 615 uint32_t initialOffset = this->addDraw(ROTATE, &size); 616 addScalar(degrees); 617 validate(initialOffset, size); 618 return this->INHERITED::rotate(degrees); 619} 620 621bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) { 622 // op + sx + sy 623 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 624 uint32_t initialOffset = this->addDraw(SKEW, &size); 625 addScalar(sx); 626 addScalar(sy); 627 validate(initialOffset, size); 628 return this->INHERITED::skew(sx, sy); 629} 630 631bool SkPictureRecord::concat(const SkMatrix& matrix) { 632 validate(fWriter.size(), 0); 633 // op + matrix index 634 uint32_t size = 2 * kUInt32Size; 635 uint32_t initialOffset = this->addDraw(CONCAT, &size); 636 addMatrix(matrix); 637 validate(initialOffset, size); 638 return this->INHERITED::concat(matrix); 639} 640 641void SkPictureRecord::setMatrix(const SkMatrix& matrix) { 642 validate(fWriter.size(), 0); 643 // op + matrix index 644 uint32_t size = 2 * kUInt32Size; 645 uint32_t initialOffset = this->addDraw(SET_MATRIX, &size); 646 addMatrix(matrix); 647 validate(initialOffset, size); 648 this->INHERITED::setMatrix(matrix); 649} 650 651static bool regionOpExpands(SkRegion::Op op) { 652 switch (op) { 653 case SkRegion::kUnion_Op: 654 case SkRegion::kXOR_Op: 655 case SkRegion::kReverseDifference_Op: 656 case SkRegion::kReplace_Op: 657 return true; 658 case SkRegion::kIntersect_Op: 659 case SkRegion::kDifference_Op: 660 return false; 661 default: 662 SkDEBUGFAIL("unknown region op"); 663 return false; 664 } 665} 666 667void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { 668 int32_t offset = fRestoreOffsetStack.top(); 669 while (offset > 0) { 670 uint32_t* peek = fWriter.peek32(offset); 671 offset = *peek; 672 *peek = restoreOffset; 673 } 674 675#ifdef SK_DEBUG 676 // assert that the final offset value points to a save verb 677 uint32_t opSize; 678 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); 679 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); 680#endif 681} 682 683void SkPictureRecord::beginRecording() { 684 // we have to call this *after* our constructor, to ensure that it gets 685 // recorded. This is balanced by restoreToCount() call from endRecording, 686 // which in-turn calls our overridden restore(), so those get recorded too. 687 fInitialSaveCount = this->save(kMatrixClip_SaveFlag); 688} 689 690void SkPictureRecord::endRecording() { 691 SkASSERT(kNoInitialSave != fInitialSaveCount); 692 this->restoreToCount(fInitialSaveCount); 693} 694 695void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { 696 if (fRestoreOffsetStack.isEmpty()) { 697 return; 698 } 699 700 if (regionOpExpands(op)) { 701 // Run back through any previous clip ops, and mark their offset to 702 // be 0, disabling their ability to trigger a jump-to-restore, otherwise 703 // they could hide this clips ability to expand the clip (i.e. go from 704 // empty to non-empty). 705 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0); 706 } 707 708 size_t offset = fWriter.size(); 709 // The RestoreOffset field is initially filled with a placeholder 710 // value that points to the offset of the previous RestoreOffset 711 // in the current stack level, thus forming a linked list so that 712 // the restore offsets can be filled in when the corresponding 713 // restore command is recorded. 714 addInt(fRestoreOffsetStack.top()); 715 fRestoreOffsetStack.top() = offset; 716} 717 718bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 719 // id + rect + clip params 720 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; 721 // recordRestoreOffsetPlaceholder doesn't always write an offset 722 if (!fRestoreOffsetStack.isEmpty()) { 723 // + restore offset 724 size += kUInt32Size; 725 } 726 uint32_t initialOffset = this->addDraw(CLIP_RECT, &size); 727 addRect(rect); 728 addInt(ClipParams_pack(op, doAA)); 729 recordRestoreOffsetPlaceholder(op); 730 731 validate(initialOffset, size); 732 return this->INHERITED::clipRect(rect, op, doAA); 733} 734 735bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 736 if (rrect.isRect()) { 737 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA); 738 } 739 740 // op + rrect + clip params 741 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; 742 // recordRestoreOffsetPlaceholder doesn't always write an offset 743 if (!fRestoreOffsetStack.isEmpty()) { 744 // + restore offset 745 size += kUInt32Size; 746 } 747 uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size); 748 addRRect(rrect); 749 addInt(ClipParams_pack(op, doAA)); 750 recordRestoreOffsetPlaceholder(op); 751 752 validate(initialOffset, size); 753 754 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 755 return this->INHERITED::clipRect(rrect.getBounds(), op, doAA); 756 } else { 757 return this->INHERITED::clipRRect(rrect, op, doAA); 758 } 759} 760 761bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 762 763 SkRect r; 764 if (!path.isInverseFillType() && path.isRect(&r)) { 765 return this->clipRect(r, op, doAA); 766 } 767 768 // op + path index + clip params 769 uint32_t size = 3 * kUInt32Size; 770 // recordRestoreOffsetPlaceholder doesn't always write an offset 771 if (!fRestoreOffsetStack.isEmpty()) { 772 // + restore offset 773 size += kUInt32Size; 774 } 775 uint32_t initialOffset = this->addDraw(CLIP_PATH, &size); 776 addPath(path); 777 addInt(ClipParams_pack(op, doAA)); 778 recordRestoreOffsetPlaceholder(op); 779 780 validate(initialOffset, size); 781 782 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 783 return this->INHERITED::clipRect(path.getBounds(), op, doAA); 784 } else { 785 return this->INHERITED::clipPath(path, op, doAA); 786 } 787} 788 789bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { 790 // op + region index + clip params 791 uint32_t size = 3 * kUInt32Size; 792 // recordRestoreOffsetPlaceholder doesn't always write an offset 793 if (!fRestoreOffsetStack.isEmpty()) { 794 // + restore offset 795 size += kUInt32Size; 796 } 797 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size); 798 addRegion(region); 799 addInt(ClipParams_pack(op, false)); 800 recordRestoreOffsetPlaceholder(op); 801 802 validate(initialOffset, size); 803 return this->INHERITED::clipRegion(region, op); 804} 805 806void SkPictureRecord::clear(SkColor color) { 807 // op + color 808 uint32_t size = 2 * kUInt32Size; 809 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size); 810 addInt(color); 811 validate(initialOffset, size); 812} 813 814void SkPictureRecord::drawPaint(const SkPaint& paint) { 815 // op + paint index 816 uint32_t size = 2 * kUInt32Size; 817 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size); 818 SkASSERT(initialOffset+getPaintOffset(DRAW_PAINT, size) == fWriter.size()); 819 addPaint(paint); 820 validate(initialOffset, size); 821} 822 823void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 824 const SkPaint& paint) { 825 // op + paint index + mode + count + point data 826 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); 827 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size); 828 SkASSERT(initialOffset+getPaintOffset(DRAW_POINTS, size) == fWriter.size()); 829 addPaint(paint); 830 addInt(mode); 831 addInt(count); 832 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 833 validate(initialOffset, size); 834} 835 836void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { 837 // op + paint index + rect 838 uint32_t size = 2 * kUInt32Size + sizeof(oval); 839 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size); 840 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size()); 841 addPaint(paint); 842 addRect(oval); 843 validate(initialOffset, size); 844} 845 846void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { 847 // op + paint index + rect 848 uint32_t size = 2 * kUInt32Size + sizeof(rect); 849 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size); 850 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size()); 851 addPaint(paint); 852 addRect(rect); 853 validate(initialOffset, size); 854} 855 856void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 857 uint32_t initialOffset, size; 858 if (rrect.isRect()) { 859 // op + paint index + rect 860 size = 2 * kUInt32Size + sizeof(SkRect); 861 initialOffset = this->addDraw(DRAW_RECT, &size); 862 SkASSERT(initialOffset+getPaintOffset(DRAW_RECT, size) == fWriter.size()); 863 addPaint(paint); 864 addRect(rrect.getBounds()); 865 } else if (rrect.isOval()) { 866 // op + paint index + rect 867 size = 2 * kUInt32Size + sizeof(SkRect); 868 initialOffset = this->addDraw(DRAW_OVAL, &size); 869 SkASSERT(initialOffset+getPaintOffset(DRAW_OVAL, size) == fWriter.size()); 870 addPaint(paint); 871 addRect(rrect.getBounds()); 872 } else { 873 // op + paint index + rrect 874 size = 2 * kUInt32Size + SkRRect::kSizeInMemory; 875 initialOffset = this->addDraw(DRAW_RRECT, &size); 876 SkASSERT(initialOffset+getPaintOffset(DRAW_RRECT, size) == fWriter.size()); 877 addPaint(paint); 878 addRRect(rrect); 879 } 880 validate(initialOffset, size); 881} 882 883void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { 884 // op + paint index + path index 885 uint32_t size = 3 * kUInt32Size; 886 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size); 887 SkASSERT(initialOffset+getPaintOffset(DRAW_PATH, size) == fWriter.size()); 888 addPaint(paint); 889 addPath(path); 890 validate(initialOffset, size); 891} 892 893void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 894 const SkPaint* paint = NULL) { 895 // op + paint index + bitmap index + left + top 896 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 897 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size); 898 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP, size) == fWriter.size()); 899 addPaintPtr(paint); 900 addBitmap(bitmap); 901 addScalar(left); 902 addScalar(top); 903 validate(initialOffset, size); 904} 905 906void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 907 const SkRect& dst, const SkPaint* paint) { 908 // id + paint index + bitmap index + bool for 'src' 909 uint32_t size = 4 * kUInt32Size; 910 if (NULL != src) { 911 size += sizeof(*src); // + rect 912 } 913 size += sizeof(dst); // + rect 914 915 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); 916 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_RECT_TO_RECT, size) == fWriter.size()); 917 addPaintPtr(paint); 918 addBitmap(bitmap); 919 addRectPtr(src); // may be null 920 addRect(dst); 921 validate(initialOffset, size); 922} 923 924void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 925 const SkPaint* paint) { 926 // id + paint index + bitmap index + matrix index 927 uint32_t size = 4 * kUInt32Size; 928 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); 929 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_MATRIX, size) == fWriter.size()); 930 addPaintPtr(paint); 931 addBitmap(bitmap); 932 addMatrix(matrix); 933 validate(initialOffset, size); 934} 935 936void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 937 const SkRect& dst, const SkPaint* paint) { 938 // op + paint index + bitmap id + center + dst rect 939 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); 940 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); 941 SkASSERT(initialOffset+getPaintOffset(DRAW_BITMAP_NINE, size) == fWriter.size()); 942 addPaintPtr(paint); 943 addBitmap(bitmap); 944 addIRect(center); 945 addRect(dst); 946 validate(initialOffset, size); 947} 948 949void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, 950 const SkPaint* paint = NULL) { 951 // op + paint index + bitmap index + left + top 952 uint32_t size = 5 * kUInt32Size; 953 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size); 954 SkASSERT(initialOffset+getPaintOffset(DRAW_SPRITE, size) == fWriter.size()); 955 addPaintPtr(paint); 956 addBitmap(bitmap); 957 addInt(left); 958 addInt(top); 959 validate(initialOffset, size); 960} 961 962// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been 963// tweaked by paint.computeFastBounds(). 964// 965static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) { 966 SkPaint::FontMetrics metrics; 967 paint.getFontMetrics(&metrics); 968 SkRect bounds; 969 // construct a rect so we can see any adjustments from the paint. 970 // we use 0,1 for left,right, just so the rect isn't empty 971 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); 972 (void)paint.computeFastBounds(bounds, &bounds); 973 topbot[0] = bounds.fTop; 974 topbot[1] = bounds.fBottom; 975} 976 977void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat, 978 SkScalar minY, SkScalar maxY) { 979 if (!flat.isTopBotWritten()) { 980 computeFontMetricsTopBottom(paint, flat.writableTopBot()); 981 SkASSERT(flat.isTopBotWritten()); 982 } 983 addScalar(flat.topBot()[0] + minY); 984 addScalar(flat.topBot()[1] + maxY); 985} 986 987void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, 988 SkScalar y, const SkPaint& paint) { 989 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 990 991 // op + paint index + length + 'length' worth of chars + x + y 992 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); 993 if (fast) { 994 size += 2 * sizeof(SkScalar); // + top & bottom 995 } 996 997 DrawType op = fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT; 998 uint32_t initialOffset = this->addDraw(op, &size); 999 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); 1000 const SkFlatData* flatPaintData = addPaint(paint); 1001 SkASSERT(flatPaintData); 1002 addText(text, byteLength); 1003 addScalar(x); 1004 addScalar(y); 1005 if (fast) { 1006 addFontMetricsTopBottom(paint, *flatPaintData, y, y); 1007 } 1008 validate(initialOffset, size); 1009} 1010 1011void SkPictureRecord::drawPosText(const void* text, size_t byteLength, 1012 const SkPoint pos[], const SkPaint& paint) { 1013 size_t points = paint.countText(text, byteLength); 1014 if (0 == points) 1015 return; 1016 1017 bool canUseDrawH = true; 1018 SkScalar minY = pos[0].fY; 1019 SkScalar maxY = pos[0].fY; 1020 // check if the caller really should have used drawPosTextH() 1021 { 1022 const SkScalar firstY = pos[0].fY; 1023 for (size_t index = 1; index < points; index++) { 1024 if (pos[index].fY != firstY) { 1025 canUseDrawH = false; 1026 if (pos[index].fY < minY) { 1027 minY = pos[index].fY; 1028 } else if (pos[index].fY > maxY) { 1029 maxY = pos[index].fY; 1030 } 1031 } 1032 } 1033 } 1034 1035 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds(); 1036 bool fast = canUseDrawH && fastBounds; 1037 1038 // op + paint index + length + 'length' worth of data + num points 1039 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1040 if (canUseDrawH) { 1041 if (fast) { 1042 size += 2 * sizeof(SkScalar); // + top & bottom 1043 } 1044 // + y-pos + actual x-point data 1045 size += sizeof(SkScalar) + points * sizeof(SkScalar); 1046 } else { 1047 // + x&y point data 1048 size += points * sizeof(SkPoint); 1049 if (fastBounds) { 1050 size += 2 * sizeof(SkScalar); // + top & bottom 1051 } 1052 } 1053 1054 DrawType op; 1055 if (fast) { 1056 op = DRAW_POS_TEXT_H_TOP_BOTTOM; 1057 } else if (canUseDrawH) { 1058 op = DRAW_POS_TEXT_H; 1059 } else if (fastBounds) { 1060 op = DRAW_POS_TEXT_TOP_BOTTOM; 1061 } else { 1062 op = DRAW_POS_TEXT; 1063 } 1064 uint32_t initialOffset = this->addDraw(op, &size); 1065 SkASSERT(initialOffset+getPaintOffset(op, size) == fWriter.size()); 1066 const SkFlatData* flatPaintData = addPaint(paint); 1067 SkASSERT(flatPaintData); 1068 addText(text, byteLength); 1069 addInt(points); 1070 1071#ifdef SK_DEBUG_SIZE 1072 size_t start = fWriter.size(); 1073#endif 1074 if (canUseDrawH) { 1075 if (fast) { 1076 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY); 1077 } 1078 addScalar(pos[0].fY); 1079 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); 1080 for (size_t index = 0; index < points; index++) 1081 *xptr++ = pos[index].fX; 1082 } else { 1083 fWriter.writeMul4(pos, points * sizeof(SkPoint)); 1084 if (fastBounds) { 1085 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); 1086 } 1087 } 1088#ifdef SK_DEBUG_SIZE 1089 fPointBytes += fWriter.size() - start; 1090 fPointWrites += points; 1091#endif 1092 validate(initialOffset, size); 1093} 1094 1095void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength, 1096 const SkScalar xpos[], SkScalar constY, 1097 const SkPaint& paint) { 1098 size_t points = paint.countText(text, byteLength); 1099 if (0 == points) 1100 return; 1101 1102 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 1103 1104 // op + paint index + length + 'length' worth of data + num points 1105 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 1106 if (fast) { 1107 size += 2 * sizeof(SkScalar); // + top & bottom 1108 } 1109 // + y + the actual points 1110 size += 1 * kUInt32Size + points * sizeof(SkScalar); 1111 1112 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, 1113 &size); 1114 const SkFlatData* flatPaintData = addPaint(paint); 1115 SkASSERT(flatPaintData); 1116 addText(text, byteLength); 1117 addInt(points); 1118 1119#ifdef SK_DEBUG_SIZE 1120 size_t start = fWriter.size(); 1121#endif 1122 if (fast) { 1123 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); 1124 } 1125 addScalar(constY); 1126 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); 1127#ifdef SK_DEBUG_SIZE 1128 fPointBytes += fWriter.size() - start; 1129 fPointWrites += points; 1130#endif 1131 validate(initialOffset, size); 1132} 1133 1134void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, 1135 const SkPath& path, const SkMatrix* matrix, 1136 const SkPaint& paint) { 1137 // op + paint index + length + 'length' worth of data + path index + matrix index 1138 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size; 1139 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); 1140 SkASSERT(initialOffset+getPaintOffset(DRAW_TEXT_ON_PATH, size) == fWriter.size()); 1141 addPaint(paint); 1142 addText(text, byteLength); 1143 addPath(path); 1144 addMatrixPtr(matrix); 1145 validate(initialOffset, size); 1146} 1147 1148void SkPictureRecord::drawPicture(SkPicture& picture) { 1149 // op + picture index 1150 uint32_t size = 2 * kUInt32Size; 1151 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size); 1152 addPicture(picture); 1153 validate(initialOffset, size); 1154} 1155 1156void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, 1157 const SkPoint vertices[], const SkPoint texs[], 1158 const SkColor colors[], SkXfermode*, 1159 const uint16_t indices[], int indexCount, 1160 const SkPaint& paint) { 1161 uint32_t flags = 0; 1162 if (texs) { 1163 flags |= DRAW_VERTICES_HAS_TEXS; 1164 } 1165 if (colors) { 1166 flags |= DRAW_VERTICES_HAS_COLORS; 1167 } 1168 if (indexCount > 0) { 1169 flags |= DRAW_VERTICES_HAS_INDICES; 1170 } 1171 1172 // op + paint index + flags + vmode + vCount + vertices 1173 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); 1174 if (flags & DRAW_VERTICES_HAS_TEXS) { 1175 size += vertexCount * sizeof(SkPoint); // + uvs 1176 } 1177 if (flags & DRAW_VERTICES_HAS_COLORS) { 1178 size += vertexCount * sizeof(SkColor); // + vert colors 1179 } 1180 if (flags & DRAW_VERTICES_HAS_INDICES) { 1181 // + num indices + indices 1182 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); 1183 } 1184 1185 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size); 1186 SkASSERT(initialOffset+getPaintOffset(DRAW_VERTICES, size) == fWriter.size()); 1187 addPaint(paint); 1188 addInt(flags); 1189 addInt(vmode); 1190 addInt(vertexCount); 1191 addPoints(vertices, vertexCount); 1192 if (flags & DRAW_VERTICES_HAS_TEXS) { 1193 addPoints(texs, vertexCount); 1194 } 1195 if (flags & DRAW_VERTICES_HAS_COLORS) { 1196 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); 1197 } 1198 if (flags & DRAW_VERTICES_HAS_INDICES) { 1199 addInt(indexCount); 1200 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); 1201 } 1202 validate(initialOffset, size); 1203} 1204 1205void SkPictureRecord::drawData(const void* data, size_t length) { 1206 // op + length + 'length' worth of data 1207 uint32_t size = 2 * kUInt32Size + SkAlign4(length); 1208 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size); 1209 addInt(length); 1210 fWriter.writePad(data, length); 1211 validate(initialOffset, size); 1212} 1213 1214/////////////////////////////////////////////////////////////////////////////// 1215 1216void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { 1217 const int index = fBitmapHeap->insert(bitmap); 1218 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In 1219 // release builds, the invalid value will be recorded so that the reader will know that there 1220 // was a problem. 1221 SkASSERT(index != SkBitmapHeap::INVALID_SLOT); 1222 addInt(index); 1223} 1224 1225void SkPictureRecord::addMatrix(const SkMatrix& matrix) { 1226 addMatrixPtr(&matrix); 1227} 1228 1229void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) { 1230 this->addInt(matrix ? fMatrices.find(*matrix) : 0); 1231} 1232 1233const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { 1234 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL; 1235 int index = data ? data->index() : 0; 1236 this->addInt(index); 1237 return data; 1238} 1239 1240void SkPictureRecord::addPath(const SkPath& path) { 1241 if (NULL == fPathHeap) { 1242 fPathHeap = SkNEW(SkPathHeap); 1243 } 1244 addInt(fPathHeap->append(path)); 1245} 1246 1247void SkPictureRecord::addPicture(SkPicture& picture) { 1248 int index = fPictureRefs.find(&picture); 1249 if (index < 0) { // not found 1250 index = fPictureRefs.count(); 1251 *fPictureRefs.append() = &picture; 1252 picture.ref(); 1253 } 1254 // follow the convention of recording a 1-based index 1255 addInt(index + 1); 1256} 1257 1258void SkPictureRecord::addPoint(const SkPoint& point) { 1259#ifdef SK_DEBUG_SIZE 1260 size_t start = fWriter.size(); 1261#endif 1262 fWriter.writePoint(point); 1263#ifdef SK_DEBUG_SIZE 1264 fPointBytes += fWriter.size() - start; 1265 fPointWrites++; 1266#endif 1267} 1268 1269void SkPictureRecord::addPoints(const SkPoint pts[], int count) { 1270 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 1271#ifdef SK_DEBUG_SIZE 1272 fPointBytes += count * sizeof(SkPoint); 1273 fPointWrites++; 1274#endif 1275} 1276 1277void SkPictureRecord::addRect(const SkRect& rect) { 1278#ifdef SK_DEBUG_SIZE 1279 size_t start = fWriter.size(); 1280#endif 1281 fWriter.writeRect(rect); 1282#ifdef SK_DEBUG_SIZE 1283 fRectBytes += fWriter.size() - start; 1284 fRectWrites++; 1285#endif 1286} 1287 1288void SkPictureRecord::addRectPtr(const SkRect* rect) { 1289 if (fWriter.writeBool(rect != NULL)) { 1290 fWriter.writeRect(*rect); 1291 } 1292} 1293 1294void SkPictureRecord::addIRect(const SkIRect& rect) { 1295 fWriter.write(&rect, sizeof(rect)); 1296} 1297 1298void SkPictureRecord::addIRectPtr(const SkIRect* rect) { 1299 if (fWriter.writeBool(rect != NULL)) { 1300 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; 1301 } 1302} 1303 1304void SkPictureRecord::addRRect(const SkRRect& rrect) { 1305 fWriter.writeRRect(rrect); 1306} 1307 1308void SkPictureRecord::addRegion(const SkRegion& region) { 1309 addInt(fRegions.find(region)); 1310} 1311 1312void SkPictureRecord::addText(const void* text, size_t byteLength) { 1313#ifdef SK_DEBUG_SIZE 1314 size_t start = fWriter.size(); 1315#endif 1316 addInt(byteLength); 1317 fWriter.writePad(text, byteLength); 1318#ifdef SK_DEBUG_SIZE 1319 fTextBytes += fWriter.size() - start; 1320 fTextWrites++; 1321#endif 1322} 1323 1324/////////////////////////////////////////////////////////////////////////////// 1325 1326#ifdef SK_DEBUG_SIZE 1327size_t SkPictureRecord::size() const { 1328 size_t result = 0; 1329 size_t sizeData; 1330 bitmaps(&sizeData); 1331 result += sizeData; 1332 matrices(&sizeData); 1333 result += sizeData; 1334 paints(&sizeData); 1335 result += sizeData; 1336 paths(&sizeData); 1337 result += sizeData; 1338 pictures(&sizeData); 1339 result += sizeData; 1340 regions(&sizeData); 1341 result += sizeData; 1342 result += streamlen(); 1343 return result; 1344} 1345 1346int SkPictureRecord::bitmaps(size_t* size) const { 1347 size_t result = 0; 1348 int count = fBitmaps.count(); 1349 for (int index = 0; index < count; index++) 1350 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size(); 1351 *size = result; 1352 return count; 1353} 1354 1355int SkPictureRecord::matrices(size_t* size) const { 1356 int count = fMatrices.count(); 1357 *size = sizeof(fMatrices[0]) * count; 1358 return count; 1359} 1360 1361int SkPictureRecord::paints(size_t* size) const { 1362 size_t result = 0; 1363 int count = fPaints.count(); 1364 for (int index = 0; index < count; index++) 1365 result += sizeof(fPaints[index]) + fPaints[index]->size(); 1366 *size = result; 1367 return count; 1368} 1369 1370int SkPictureRecord::paths(size_t* size) const { 1371 size_t result = 0; 1372 int count = fPaths.count(); 1373 for (int index = 0; index < count; index++) 1374 result += sizeof(fPaths[index]) + fPaths[index]->size(); 1375 *size = result; 1376 return count; 1377} 1378 1379int SkPictureRecord::regions(size_t* size) const { 1380 size_t result = 0; 1381 int count = fRegions.count(); 1382 for (int index = 0; index < count; index++) 1383 result += sizeof(fRegions[index]) + fRegions[index]->size(); 1384 *size = result; 1385 return count; 1386} 1387 1388size_t SkPictureRecord::streamlen() const { 1389 return fWriter.size(); 1390} 1391#endif 1392 1393#ifdef SK_DEBUG_VALIDATE 1394void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const { 1395 SkASSERT(fWriter.size() == initialOffset + size); 1396 1397 validateBitmaps(); 1398 validateMatrices(); 1399 validatePaints(); 1400 validatePaths(); 1401 validateRegions(); 1402} 1403 1404void SkPictureRecord::validateBitmaps() const { 1405 int count = fBitmapHeap->count(); 1406 SkASSERT((unsigned) count < 0x1000); 1407 for (int index = 0; index < count; index++) { 1408 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index); 1409 SkASSERT(bitPtr); 1410 bitPtr->validate(); 1411 } 1412} 1413 1414void SkPictureRecord::validateMatrices() const { 1415 int count = fMatrices.count(); 1416 SkASSERT((unsigned) count < 0x1000); 1417 for (int index = 0; index < count; index++) { 1418 const SkFlatData* matrix = fMatrices[index]; 1419 SkASSERT(matrix); 1420// matrix->validate(); 1421 } 1422} 1423 1424void SkPictureRecord::validatePaints() const { 1425 int count = fPaints.count(); 1426 SkASSERT((unsigned) count < 0x1000); 1427 for (int index = 0; index < count; index++) { 1428 const SkFlatData* paint = fPaints[index]; 1429 SkASSERT(paint); 1430// paint->validate(); 1431 } 1432} 1433 1434void SkPictureRecord::validatePaths() const { 1435 if (NULL == fPathHeap) { 1436 return; 1437 } 1438 1439 int count = fPathHeap->count(); 1440 SkASSERT((unsigned) count < 0x1000); 1441 for (int index = 0; index < count; index++) { 1442 const SkPath& path = (*fPathHeap)[index]; 1443 path.validate(); 1444 } 1445} 1446 1447void SkPictureRecord::validateRegions() const { 1448 int count = fRegions.count(); 1449 SkASSERT((unsigned) count < 0x1000); 1450 for (int index = 0; index < count; index++) { 1451 const SkFlatData* region = fRegions[index]; 1452 SkASSERT(region); 1453// region->validate(); 1454 } 1455} 1456#endif 1457