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