SkPictureRecord.cpp revision e4ce5b82627d7ef7cab34b808ff88dc208aef7bc
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 26SkPictureRecord::SkPictureRecord(uint32_t flags, SkDevice* device) : 27 INHERITED(device), 28 fBoundingHierarchy(NULL), 29 fStateTree(NULL), 30 fFlattenableHeap(HEAP_BLOCK_SIZE), 31 fMatrices(&fFlattenableHeap), 32 fPaints(&fFlattenableHeap), 33 fRegions(&fFlattenableHeap), 34 fWriter(MIN_WRITER_SIZE), 35 fRecordFlags(flags) { 36#ifdef SK_DEBUG_SIZE 37 fPointBytes = fRectBytes = fTextBytes = 0; 38 fPointWrites = fRectWrites = fTextWrites = 0; 39#endif 40 41 fRestoreOffsetStack.setReserve(32); 42 43 fBitmapHeap = SkNEW(SkBitmapHeap); 44 fFlattenableHeap.setBitmapStorage(fBitmapHeap); 45 fPathHeap = NULL; // lazy allocate 46 fFirstSavedLayerIndex = kNoSavedLayerIndex; 47 48 fInitialSaveCount = kNoInitialSave; 49} 50 51SkPictureRecord::~SkPictureRecord() { 52 SkSafeUnref(fBitmapHeap); 53 SkSafeUnref(fPathHeap); 54 SkSafeUnref(fBoundingHierarchy); 55 SkSafeUnref(fStateTree); 56 fFlattenableHeap.setBitmapStorage(NULL); 57 fPictureRefs.unrefAll(); 58} 59 60/////////////////////////////////////////////////////////////////////////////// 61 62SkDevice* SkPictureRecord::setDevice(SkDevice* device) { 63 SkASSERT(!"eeek, don't try to change the device on a recording canvas"); 64 return this->INHERITED::setDevice(device); 65} 66 67int SkPictureRecord::save(SaveFlags flags) { 68 // record the offset to us, making it non-positive to distinguish a save 69 // from a clip entry. 70 fRestoreOffsetStack.push(-(int32_t)fWriter.size()); 71 72 // op + flags 73 uint32_t size = 2 * kUInt32Size; 74 uint32_t initialOffset = this->addDraw(SAVE, &size); 75 addInt(flags); 76 77 validate(initialOffset, size); 78 return this->INHERITED::save(flags); 79} 80 81int SkPictureRecord::saveLayer(const SkRect* bounds, const SkPaint* paint, 82 SaveFlags flags) { 83 // record the offset to us, making it non-positive to distinguish a save 84 // from a clip entry. 85 fRestoreOffsetStack.push(-(int32_t)fWriter.size()); 86 87 // op + bool for 'bounds' 88 uint32_t size = 2 * kUInt32Size; 89 if (NULL != bounds) { 90 size += sizeof(*bounds); // + rect 91 } 92 // + paint index + flags 93 size += 2 * kUInt32Size; 94 95 uint32_t initialOffset = this->addDraw(SAVE_LAYER, &size); 96 addRectPtr(bounds); 97 addPaintPtr(paint); 98 addInt(flags); 99 100 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) { 101 fFirstSavedLayerIndex = fRestoreOffsetStack.count(); 102 } 103 104 validate(initialOffset, size); 105 /* Don't actually call saveLayer, because that will try to allocate an 106 offscreen device (potentially very big) which we don't actually need 107 at this time (and may not be able to afford since during record our 108 clip starts out the size of the picture, which is often much larger 109 than the size of the actual device we'll use during playback). 110 */ 111 int count = this->INHERITED::save(flags); 112 this->clipRectBounds(bounds, flags, NULL); 113 return count; 114} 115 116bool SkPictureRecord::isDrawingToLayer() const { 117 return fFirstSavedLayerIndex != kNoSavedLayerIndex; 118} 119 120/* 121 * Read the op code from 'offset' in 'writer' and extract the size too. 122 */ 123static DrawType peek_op_and_size(SkWriter32* writer, int32_t offset, uint32_t* size) { 124 uint32_t* peek = writer->peek32(offset); 125 126 uint32_t op; 127 UNPACK_8_24(*peek, op, *size); 128 if (MASK_24 == *size) { 129 // size required its own slot right after the op code 130 *size = *writer->peek32(offset+kUInt32Size); 131 } 132 return (DrawType) op; 133} 134 135#ifdef TRACK_COLLAPSE_STATS 136 static int gCollapseCount, gCollapseCalls; 137#endif 138 139/* 140 * Restore has just been called (but not recoreded), so look back at the 141 * matching save(), and see if we can eliminate the pair of them, due to no 142 * intervening matrix/clip calls. 143 * 144 * If so, update the writer and return true, in which case we won't even record 145 * the restore() call. If we still need the restore(), return false. 146 */ 147static bool collapseSaveClipRestore(SkWriter32* writer, int32_t offset) { 148#ifdef TRACK_COLLAPSE_STATS 149 gCollapseCalls += 1; 150#endif 151 152 int32_t restoreOffset = (int32_t)writer->size(); 153 154 // back up to the save block 155 while (offset > 0) { 156 offset = *writer->peek32(offset); 157 } 158 159 // now offset points to a save 160 offset = -offset; 161 uint32_t opSize; 162 DrawType op = peek_op_and_size(writer, offset, &opSize); 163 if (SAVE_LAYER == op) { 164 // not ready to cull these out yet (mrr) 165 return false; 166 } 167 SkASSERT(SAVE == op); 168 169 // Walk forward until we get back to either a draw-verb (abort) or we hit 170 // our restore (success). 171 int32_t saveOffset = offset; 172 173 offset += opSize; 174 while (offset < restoreOffset) { 175 op = peek_op_and_size(writer, offset, &opSize); 176 if ((op > CONCAT && op < ROTATE) || (SAVE_LAYER == op)) { 177 // drawing verb, abort 178 return false; 179 } 180 offset += opSize; 181 } 182 183#ifdef TRACK_COLLAPSE_STATS 184 gCollapseCount += 1; 185 SkDebugf("Collapse [%d out of %d] %g%spn", gCollapseCount, gCollapseCalls, 186 (double)gCollapseCount / gCollapseCalls, "%"); 187#endif 188 189 writer->rewindToOffset(saveOffset); 190 return true; 191} 192 193// This function is just a toy example and will not be delivered with this 194// CL 195static bool noClips(SkWriter32* writer, int32_t offset) { 196 197 int32_t restoreOffset = (int32_t)writer->size(); 198 199 // back up to the save block 200 while (offset > 0) { 201 offset = *writer->peek32(offset); 202 } 203 204 // now offset points to a save 205 offset = -offset; 206 uint32_t opSize; 207 DrawType op = peek_op_and_size(writer, offset, &opSize); 208 SkASSERT(SAVE == op || SAVE_LAYER == op); 209 210 // Walk forward until until we hit our restore, nuking all clips 211 // along the way 212 offset += opSize; 213 while (offset < restoreOffset) { 214 op = peek_op_and_size(writer, offset, &opSize); 215 216 if (CLIP_RECT == op || CLIP_RRECT == op) { 217 uint32_t* ptr = writer->peek32(offset); 218 *ptr = (*ptr & MASK_24) | (NOOP << 24); 219 } 220 offset += opSize; 221 } 222 223 return true; 224} 225 226void SkPictureRecord::restore() { 227 // FIXME: SkDeferredCanvas needs to be refactored to respect 228 // save/restore balancing so that the following test can be 229 // turned on permanently. 230#if 0 231 SkASSERT(fRestoreOffsetStack.count() > 1); 232#endif 233 234 // check for underflow 235 if (fRestoreOffsetStack.count() == 0) { 236 return; 237 } 238 239 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) { 240 fFirstSavedLayerIndex = kNoSavedLayerIndex; 241 } 242 243 // This call will not be delivered either 244 noClips(&fWriter, fRestoreOffsetStack.top()); 245 246 uint32_t initialOffset, size; 247 if (!collapseSaveClipRestore(&fWriter, fRestoreOffsetStack.top())) { 248 fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.size()); 249 // op 250 size = 1 * kUInt32Size; 251 initialOffset = this->addDraw(RESTORE, &size); 252 } else { 253 size = 0; 254 initialOffset = fWriter.size(); 255 } 256 257 fRestoreOffsetStack.pop(); 258 259 validate(initialOffset, size); 260 return this->INHERITED::restore(); 261} 262 263bool SkPictureRecord::translate(SkScalar dx, SkScalar dy) { 264 // op + dx + dy 265 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 266 uint32_t initialOffset = this->addDraw(TRANSLATE, &size); 267 addScalar(dx); 268 addScalar(dy); 269 validate(initialOffset, size); 270 return this->INHERITED::translate(dx, dy); 271} 272 273bool SkPictureRecord::scale(SkScalar sx, SkScalar sy) { 274 // op + sx + sy 275 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 276 uint32_t initialOffset = this->addDraw(SCALE, &size); 277 addScalar(sx); 278 addScalar(sy); 279 validate(initialOffset, size); 280 return this->INHERITED::scale(sx, sy); 281} 282 283bool SkPictureRecord::rotate(SkScalar degrees) { 284 // op + degrees 285 uint32_t size = 1 * kUInt32Size + sizeof(SkScalar); 286 uint32_t initialOffset = this->addDraw(ROTATE, &size); 287 addScalar(degrees); 288 validate(initialOffset, size); 289 return this->INHERITED::rotate(degrees); 290} 291 292bool SkPictureRecord::skew(SkScalar sx, SkScalar sy) { 293 // op + sx + sy 294 uint32_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 295 uint32_t initialOffset = this->addDraw(SKEW, &size); 296 addScalar(sx); 297 addScalar(sy); 298 validate(initialOffset, size); 299 return this->INHERITED::skew(sx, sy); 300} 301 302bool SkPictureRecord::concat(const SkMatrix& matrix) { 303 validate(fWriter.size(), 0); 304 // op + matrix index 305 uint32_t size = 2 * kUInt32Size; 306 uint32_t initialOffset = this->addDraw(CONCAT, &size); 307 addMatrix(matrix); 308 validate(initialOffset, size); 309 return this->INHERITED::concat(matrix); 310} 311 312void SkPictureRecord::setMatrix(const SkMatrix& matrix) { 313 validate(fWriter.size(), 0); 314 // op + matrix index 315 uint32_t size = 2 * kUInt32Size; 316 uint32_t initialOffset = this->addDraw(SET_MATRIX, &size); 317 addMatrix(matrix); 318 validate(initialOffset, size); 319 this->INHERITED::setMatrix(matrix); 320} 321 322static bool regionOpExpands(SkRegion::Op op) { 323 switch (op) { 324 case SkRegion::kUnion_Op: 325 case SkRegion::kXOR_Op: 326 case SkRegion::kReverseDifference_Op: 327 case SkRegion::kReplace_Op: 328 return true; 329 case SkRegion::kIntersect_Op: 330 case SkRegion::kDifference_Op: 331 return false; 332 default: 333 SkDEBUGFAIL("unknown region op"); 334 return false; 335 } 336} 337 338void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel( 339 uint32_t restoreOffset) { 340 int32_t offset = fRestoreOffsetStack.top(); 341 while (offset > 0) { 342 uint32_t* peek = fWriter.peek32(offset); 343 offset = *peek; 344 *peek = restoreOffset; 345 } 346 347#ifdef SK_DEBUG 348 // assert that the final offset value points to a save verb 349 uint32_t opSize; 350 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); 351 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); 352#endif 353} 354 355void SkPictureRecord::beginRecording() { 356 // we have to call this *after* our constructor, to ensure that it gets 357 // recorded. This is balanced by restoreToCount() call from endRecording, 358 // which in-turn calls our overridden restore(), so those get recorded too. 359 fInitialSaveCount = this->save(kMatrixClip_SaveFlag); 360} 361 362void SkPictureRecord::endRecording() { 363 SkASSERT(kNoInitialSave != fInitialSaveCount); 364 this->restoreToCount(fInitialSaveCount); 365} 366 367void SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { 368 if (fRestoreOffsetStack.isEmpty()) { 369 return; 370 } 371 372 if (regionOpExpands(op)) { 373 // Run back through any previous clip ops, and mark their offset to 374 // be 0, disabling their ability to trigger a jump-to-restore, otherwise 375 // they could hide this clips ability to expand the clip (i.e. go from 376 // empty to non-empty). 377 fillRestoreOffsetPlaceholdersForCurrentStackLevel(0); 378 } 379 380 size_t offset = fWriter.size(); 381 // The RestoreOffset field is initially filled with a placeholder 382 // value that points to the offset of the previous RestoreOffset 383 // in the current stack level, thus forming a linked list so that 384 // the restore offsets can be filled in when the corresponding 385 // restore command is recorded. 386 addInt(fRestoreOffsetStack.top()); 387 fRestoreOffsetStack.top() = offset; 388} 389 390bool SkPictureRecord::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 391 // id + rect + clip params 392 uint32_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; 393 if (!fRestoreOffsetStack.isEmpty()) { 394 // + restore offset 395 size += kUInt32Size; 396 } 397 uint32_t initialOffset = this->addDraw(CLIP_RECT, &size); 398 addRect(rect); 399 addInt(ClipParams_pack(op, doAA)); 400 recordRestoreOffsetPlaceholder(op); 401 402 validate(initialOffset, size); 403 return this->INHERITED::clipRect(rect, op, doAA); 404} 405 406bool SkPictureRecord::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 407 if (rrect.isRect()) { 408 return this->SkPictureRecord::clipRect(rrect.getBounds(), op, doAA); 409 } 410 411 // op + rrect + clip params 412 uint32_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; 413 if (!fRestoreOffsetStack.isEmpty()) { 414 // + restore offset 415 size += kUInt32Size; 416 } 417 uint32_t initialOffset = this->addDraw(CLIP_RRECT, &size); 418 addRRect(rrect); 419 addInt(ClipParams_pack(op, doAA)); 420 recordRestoreOffsetPlaceholder(op); 421 422 validate(initialOffset, size); 423 424 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 425 return this->INHERITED::clipRect(rrect.getBounds(), op, doAA); 426 } else { 427 return this->INHERITED::clipRRect(rrect, op, doAA); 428 } 429} 430 431bool SkPictureRecord::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 432 433 SkRect r; 434 if (!path.isInverseFillType() && path.isRect(&r)) { 435 return this->clipRect(r, op, doAA); 436 } 437 438 // op + path index + clip params 439 uint32_t size = 3 * kUInt32Size; 440 if (!fRestoreOffsetStack.isEmpty()) { 441 // + restore offset 442 size += kUInt32Size; 443 } 444 uint32_t initialOffset = this->addDraw(CLIP_PATH, &size); 445 addPath(path); 446 addInt(ClipParams_pack(op, doAA)); 447 recordRestoreOffsetPlaceholder(op); 448 449 validate(initialOffset, size); 450 451 if (fRecordFlags & SkPicture::kUsePathBoundsForClip_RecordingFlag) { 452 return this->INHERITED::clipRect(path.getBounds(), op, doAA); 453 } else { 454 return this->INHERITED::clipPath(path, op, doAA); 455 } 456} 457 458bool SkPictureRecord::clipRegion(const SkRegion& region, SkRegion::Op op) { 459 // op + region index + clip params 460 uint32_t size = 3 * kUInt32Size; 461 if (!fRestoreOffsetStack.isEmpty()) { 462 // + restore offset 463 size += kUInt32Size; 464 } 465 uint32_t initialOffset = this->addDraw(CLIP_REGION, &size); 466 addRegion(region); 467 addInt(ClipParams_pack(op, false)); 468 recordRestoreOffsetPlaceholder(op); 469 470 validate(initialOffset, size); 471 return this->INHERITED::clipRegion(region, op); 472} 473 474void SkPictureRecord::clear(SkColor color) { 475 // op + color 476 uint32_t size = 2 * kUInt32Size; 477 uint32_t initialOffset = this->addDraw(DRAW_CLEAR, &size); 478 addInt(color); 479 validate(initialOffset, size); 480} 481 482void SkPictureRecord::drawPaint(const SkPaint& paint) { 483 // op + paint index 484 uint32_t size = 2 * kUInt32Size; 485 uint32_t initialOffset = this->addDraw(DRAW_PAINT, &size); 486 addPaint(paint); 487 validate(initialOffset, size); 488} 489 490void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 491 const SkPaint& paint) { 492 // op + paint index + mode + count + point data 493 uint32_t size = 4 * kUInt32Size + count * sizeof(SkPoint); 494 uint32_t initialOffset = this->addDraw(DRAW_POINTS, &size); 495 addPaint(paint); 496 addInt(mode); 497 addInt(count); 498 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 499 validate(initialOffset, size); 500} 501 502void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { 503 // op + paint index + rect 504 uint32_t size = 2 * kUInt32Size + sizeof(oval); 505 uint32_t initialOffset = this->addDraw(DRAW_OVAL, &size); 506 addPaint(paint); 507 addRect(oval); 508 validate(initialOffset, size); 509} 510 511void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { 512 // op + paint index + rect 513 uint32_t size = 2 * kUInt32Size + sizeof(rect); 514 uint32_t initialOffset = this->addDraw(DRAW_RECT, &size); 515 addPaint(paint); 516 addRect(rect); 517 validate(initialOffset, size); 518} 519 520void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 521 uint32_t initialOffset, size; 522 if (rrect.isRect()) { 523 // op + paint index + rect 524 size = 2 * kUInt32Size + sizeof(SkRect); 525 initialOffset = this->addDraw(DRAW_RECT, &size); 526 addPaint(paint); 527 addRect(rrect.getBounds()); 528 } else if (rrect.isOval()) { 529 // op + paint index + rect 530 size = 2 * kUInt32Size + sizeof(SkRect); 531 initialOffset = this->addDraw(DRAW_OVAL, &size); 532 addPaint(paint); 533 addRect(rrect.getBounds()); 534 } else { 535 // op + paint index + rrect 536 size = 2 * kUInt32Size + SkRRect::kSizeInMemory; 537 initialOffset = this->addDraw(DRAW_RRECT, &size); 538 addPaint(paint); 539 addRRect(rrect); 540 } 541 validate(initialOffset, size); 542} 543 544void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { 545 // op + paint index + path index 546 uint32_t size = 3 * kUInt32Size; 547 uint32_t initialOffset = this->addDraw(DRAW_PATH, &size); 548 addPaint(paint); 549 addPath(path); 550 validate(initialOffset, size); 551} 552 553void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 554 const SkPaint* paint = NULL) { 555 // op + paint index + bitmap index + left + top 556 uint32_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 557 uint32_t initialOffset = this->addDraw(DRAW_BITMAP, &size); 558 addPaintPtr(paint); 559 addBitmap(bitmap); 560 addScalar(left); 561 addScalar(top); 562 validate(initialOffset, size); 563} 564 565void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 566 const SkRect& dst, const SkPaint* paint) { 567 // id + paint index + bitmap index + bool for 'src' 568 uint32_t size = 4 * kUInt32Size; 569 if (NULL != src) { 570 size += sizeof(*src); // + rect 571 } 572 size += sizeof(dst); // + rect 573 574 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); 575 addPaintPtr(paint); 576 addBitmap(bitmap); 577 addRectPtr(src); // may be null 578 addRect(dst); 579 validate(initialOffset, size); 580} 581 582void SkPictureRecord::drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& matrix, 583 const SkPaint* paint) { 584 // id + paint index + bitmap index + matrix index 585 uint32_t size = 4 * kUInt32Size; 586 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_MATRIX, &size); 587 addPaintPtr(paint); 588 addBitmap(bitmap); 589 addMatrix(matrix); 590 validate(initialOffset, size); 591} 592 593void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 594 const SkRect& dst, const SkPaint* paint) { 595 // op + paint index + bitmap id + center + dst rect 596 uint32_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); 597 uint32_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); 598 addPaintPtr(paint); 599 addBitmap(bitmap); 600 addIRect(center); 601 addRect(dst); 602 validate(initialOffset, size); 603} 604 605void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, 606 const SkPaint* paint = NULL) { 607 // op + paint index + bitmap index + left + top 608 uint32_t size = 5 * kUInt32Size; 609 uint32_t initialOffset = this->addDraw(DRAW_SPRITE, &size); 610 addPaintPtr(paint); 611 addBitmap(bitmap); 612 addInt(left); 613 addInt(top); 614 validate(initialOffset, size); 615} 616 617// Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been 618// tweaked by paint.computeFastBounds(). 619// 620static void computeFontMetricsTopBottom(const SkPaint& paint, SkScalar topbot[2]) { 621 SkPaint::FontMetrics metrics; 622 paint.getFontMetrics(&metrics); 623 SkRect bounds; 624 // construct a rect so we can see any adjustments from the paint. 625 // we use 0,1 for left,right, just so the rect isn't empty 626 bounds.set(0, metrics.fTop, SK_Scalar1, metrics.fBottom); 627 (void)paint.computeFastBounds(bounds, &bounds); 628 topbot[0] = bounds.fTop; 629 topbot[1] = bounds.fBottom; 630} 631 632void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint, const SkFlatData& flat, 633 SkScalar minY, SkScalar maxY) { 634 if (!flat.isTopBotWritten()) { 635 computeFontMetricsTopBottom(paint, flat.writableTopBot()); 636 SkASSERT(flat.isTopBotWritten()); 637 } 638 addScalar(flat.topBot()[0] + minY); 639 addScalar(flat.topBot()[1] + maxY); 640} 641 642void SkPictureRecord::drawText(const void* text, size_t byteLength, SkScalar x, 643 SkScalar y, const SkPaint& paint) { 644 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 645 646 // op + paint index + length + 'length' worth of chars + x + y 647 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); 648 if (fast) { 649 size += 2 * sizeof(SkScalar); // + top & bottom 650 } 651 652 uint32_t initialOffset = this->addDraw(fast ? DRAW_TEXT_TOP_BOTTOM : DRAW_TEXT, &size); 653 const SkFlatData* flatPaintData = addPaint(paint); 654 SkASSERT(flatPaintData); 655 addText(text, byteLength); 656 addScalar(x); 657 addScalar(y); 658 if (fast) { 659 addFontMetricsTopBottom(paint, *flatPaintData, y, y); 660 } 661 validate(initialOffset, size); 662} 663 664void SkPictureRecord::drawPosText(const void* text, size_t byteLength, 665 const SkPoint pos[], const SkPaint& paint) { 666 size_t points = paint.countText(text, byteLength); 667 if (0 == points) 668 return; 669 670 bool canUseDrawH = true; 671 SkScalar minY = pos[0].fY; 672 SkScalar maxY = pos[0].fY; 673 // check if the caller really should have used drawPosTextH() 674 { 675 const SkScalar firstY = pos[0].fY; 676 for (size_t index = 1; index < points; index++) { 677 if (pos[index].fY != firstY) { 678 canUseDrawH = false; 679 if (pos[index].fY < minY) { 680 minY = pos[index].fY; 681 } else if (pos[index].fY > maxY) { 682 maxY = pos[index].fY; 683 } 684 } 685 } 686 } 687 688 bool fastBounds = !paint.isVerticalText() && paint.canComputeFastBounds(); 689 bool fast = canUseDrawH && fastBounds; 690 691 // op + paint index + length + 'length' worth of data + num points 692 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 693 if (canUseDrawH) { 694 if (fast) { 695 size += 2 * sizeof(SkScalar); // + top & bottom 696 } 697 // + y-pos + actual x-point data 698 size += sizeof(SkScalar) + points * sizeof(SkScalar); 699 } else { 700 // + x&y point data 701 size += points * sizeof(SkPoint); 702 if (fastBounds) { 703 size += 2 * sizeof(SkScalar); // + top & bottom 704 } 705 } 706 707 DrawType op; 708 if (fast) { 709 op = DRAW_POS_TEXT_H_TOP_BOTTOM; 710 } else if (canUseDrawH) { 711 op = DRAW_POS_TEXT_H; 712 } else if (fastBounds) { 713 op = DRAW_POS_TEXT_TOP_BOTTOM; 714 } else { 715 op = DRAW_POS_TEXT; 716 } 717 uint32_t initialOffset = this->addDraw(op, &size); 718 const SkFlatData* flatPaintData = addPaint(paint); 719 SkASSERT(flatPaintData); 720 addText(text, byteLength); 721 addInt(points); 722 723#ifdef SK_DEBUG_SIZE 724 size_t start = fWriter.size(); 725#endif 726 if (canUseDrawH) { 727 if (fast) { 728 addFontMetricsTopBottom(paint, *flatPaintData, pos[0].fY, pos[0].fY); 729 } 730 addScalar(pos[0].fY); 731 SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar)); 732 for (size_t index = 0; index < points; index++) 733 *xptr++ = pos[index].fX; 734 } else { 735 fWriter.writeMul4(pos, points * sizeof(SkPoint)); 736 if (fastBounds) { 737 addFontMetricsTopBottom(paint, *flatPaintData, minY, maxY); 738 } 739 } 740#ifdef SK_DEBUG_SIZE 741 fPointBytes += fWriter.size() - start; 742 fPointWrites += points; 743#endif 744 validate(initialOffset, size); 745} 746 747void SkPictureRecord::drawPosTextH(const void* text, size_t byteLength, 748 const SkScalar xpos[], SkScalar constY, 749 const SkPaint& paint) { 750 size_t points = paint.countText(text, byteLength); 751 if (0 == points) 752 return; 753 754 bool fast = !paint.isVerticalText() && paint.canComputeFastBounds(); 755 756 // op + paint index + length + 'length' worth of data + num points 757 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 758 if (fast) { 759 size += 2 * sizeof(SkScalar); // + top & bottom 760 } 761 // + y + the actual points 762 size += 1 * kUInt32Size + points * sizeof(SkScalar); 763 764 uint32_t initialOffset = this->addDraw(fast ? DRAW_POS_TEXT_H_TOP_BOTTOM : DRAW_POS_TEXT_H, 765 &size); 766 const SkFlatData* flatPaintData = addPaint(paint); 767 SkASSERT(flatPaintData); 768 addText(text, byteLength); 769 addInt(points); 770 771#ifdef SK_DEBUG_SIZE 772 size_t start = fWriter.size(); 773#endif 774 if (fast) { 775 addFontMetricsTopBottom(paint, *flatPaintData, constY, constY); 776 } 777 addScalar(constY); 778 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); 779#ifdef SK_DEBUG_SIZE 780 fPointBytes += fWriter.size() - start; 781 fPointWrites += points; 782#endif 783 validate(initialOffset, size); 784} 785 786void SkPictureRecord::drawTextOnPath(const void* text, size_t byteLength, 787 const SkPath& path, const SkMatrix* matrix, 788 const SkPaint& paint) { 789 // op + paint index + length + 'length' worth of data + path index + matrix index 790 uint32_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * kUInt32Size; 791 uint32_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); 792 addPaint(paint); 793 addText(text, byteLength); 794 addPath(path); 795 addMatrixPtr(matrix); 796 validate(initialOffset, size); 797} 798 799void SkPictureRecord::drawPicture(SkPicture& picture) { 800 // op + picture index 801 uint32_t size = 2 * kUInt32Size; 802 uint32_t initialOffset = this->addDraw(DRAW_PICTURE, &size); 803 addPicture(picture); 804 validate(initialOffset, size); 805} 806 807void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, 808 const SkPoint vertices[], const SkPoint texs[], 809 const SkColor colors[], SkXfermode*, 810 const uint16_t indices[], int indexCount, 811 const SkPaint& paint) { 812 uint32_t flags = 0; 813 if (texs) { 814 flags |= DRAW_VERTICES_HAS_TEXS; 815 } 816 if (colors) { 817 flags |= DRAW_VERTICES_HAS_COLORS; 818 } 819 if (indexCount > 0) { 820 flags |= DRAW_VERTICES_HAS_INDICES; 821 } 822 823 // op + paint index + flags + vmode + vCount + vertices 824 uint32_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); 825 if (flags & DRAW_VERTICES_HAS_TEXS) { 826 size += vertexCount * sizeof(SkPoint); // + uvs 827 } 828 if (flags & DRAW_VERTICES_HAS_COLORS) { 829 size += vertexCount * sizeof(SkColor); // + vert colors 830 } 831 if (flags & DRAW_VERTICES_HAS_INDICES) { 832 // + num indices + indices 833 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); 834 } 835 836 uint32_t initialOffset = this->addDraw(DRAW_VERTICES, &size); 837 addPaint(paint); 838 addInt(flags); 839 addInt(vmode); 840 addInt(vertexCount); 841 addPoints(vertices, vertexCount); 842 if (flags & DRAW_VERTICES_HAS_TEXS) { 843 addPoints(texs, vertexCount); 844 } 845 if (flags & DRAW_VERTICES_HAS_COLORS) { 846 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); 847 } 848 if (flags & DRAW_VERTICES_HAS_INDICES) { 849 addInt(indexCount); 850 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); 851 } 852 validate(initialOffset, size); 853} 854 855void SkPictureRecord::drawData(const void* data, size_t length) { 856 // op + length + 'length' worth of data 857 uint32_t size = 2 * kUInt32Size + SkAlign4(length); 858 uint32_t initialOffset = this->addDraw(DRAW_DATA, &size); 859 addInt(length); 860 fWriter.writePad(data, length); 861 validate(initialOffset, size); 862} 863 864/////////////////////////////////////////////////////////////////////////////// 865 866void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { 867 const int index = fBitmapHeap->insert(bitmap); 868 // In debug builds, a bad return value from insert() will crash, allowing for debugging. In 869 // release builds, the invalid value will be recorded so that the reader will know that there 870 // was a problem. 871 SkASSERT(index != SkBitmapHeap::INVALID_SLOT); 872 addInt(index); 873} 874 875void SkPictureRecord::addMatrix(const SkMatrix& matrix) { 876 addMatrixPtr(&matrix); 877} 878 879void SkPictureRecord::addMatrixPtr(const SkMatrix* matrix) { 880 this->addInt(matrix ? fMatrices.find(*matrix) : 0); 881} 882 883const SkFlatData* SkPictureRecord::addPaintPtr(const SkPaint* paint) { 884 const SkFlatData* data = paint ? fPaints.findAndReturnFlat(*paint) : NULL; 885 int index = data ? data->index() : 0; 886 this->addInt(index); 887 return data; 888} 889 890void SkPictureRecord::addPath(const SkPath& path) { 891 if (NULL == fPathHeap) { 892 fPathHeap = SkNEW(SkPathHeap); 893 } 894 addInt(fPathHeap->append(path)); 895} 896 897void SkPictureRecord::addPicture(SkPicture& picture) { 898 int index = fPictureRefs.find(&picture); 899 if (index < 0) { // not found 900 index = fPictureRefs.count(); 901 *fPictureRefs.append() = &picture; 902 picture.ref(); 903 } 904 // follow the convention of recording a 1-based index 905 addInt(index + 1); 906} 907 908void SkPictureRecord::addPoint(const SkPoint& point) { 909#ifdef SK_DEBUG_SIZE 910 size_t start = fWriter.size(); 911#endif 912 fWriter.writePoint(point); 913#ifdef SK_DEBUG_SIZE 914 fPointBytes += fWriter.size() - start; 915 fPointWrites++; 916#endif 917} 918 919void SkPictureRecord::addPoints(const SkPoint pts[], int count) { 920 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 921#ifdef SK_DEBUG_SIZE 922 fPointBytes += count * sizeof(SkPoint); 923 fPointWrites++; 924#endif 925} 926 927void SkPictureRecord::addRect(const SkRect& rect) { 928#ifdef SK_DEBUG_SIZE 929 size_t start = fWriter.size(); 930#endif 931 fWriter.writeRect(rect); 932#ifdef SK_DEBUG_SIZE 933 fRectBytes += fWriter.size() - start; 934 fRectWrites++; 935#endif 936} 937 938void SkPictureRecord::addRectPtr(const SkRect* rect) { 939 if (fWriter.writeBool(rect != NULL)) { 940 fWriter.writeRect(*rect); 941 } 942} 943 944void SkPictureRecord::addIRect(const SkIRect& rect) { 945 fWriter.write(&rect, sizeof(rect)); 946} 947 948void SkPictureRecord::addIRectPtr(const SkIRect* rect) { 949 if (fWriter.writeBool(rect != NULL)) { 950 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; 951 } 952} 953 954void SkPictureRecord::addRRect(const SkRRect& rrect) { 955 fWriter.writeRRect(rrect); 956} 957 958void SkPictureRecord::addRegion(const SkRegion& region) { 959 addInt(fRegions.find(region)); 960} 961 962void SkPictureRecord::addText(const void* text, size_t byteLength) { 963#ifdef SK_DEBUG_SIZE 964 size_t start = fWriter.size(); 965#endif 966 addInt(byteLength); 967 fWriter.writePad(text, byteLength); 968#ifdef SK_DEBUG_SIZE 969 fTextBytes += fWriter.size() - start; 970 fTextWrites++; 971#endif 972} 973 974/////////////////////////////////////////////////////////////////////////////// 975 976#ifdef SK_DEBUG_SIZE 977size_t SkPictureRecord::size() const { 978 size_t result = 0; 979 size_t sizeData; 980 bitmaps(&sizeData); 981 result += sizeData; 982 matrices(&sizeData); 983 result += sizeData; 984 paints(&sizeData); 985 result += sizeData; 986 paths(&sizeData); 987 result += sizeData; 988 pictures(&sizeData); 989 result += sizeData; 990 regions(&sizeData); 991 result += sizeData; 992 result += streamlen(); 993 return result; 994} 995 996int SkPictureRecord::bitmaps(size_t* size) const { 997 size_t result = 0; 998 int count = fBitmaps.count(); 999 for (int index = 0; index < count; index++) 1000 result += sizeof(fBitmaps[index]) + fBitmaps[index]->size(); 1001 *size = result; 1002 return count; 1003} 1004 1005int SkPictureRecord::matrices(size_t* size) const { 1006 int count = fMatrices.count(); 1007 *size = sizeof(fMatrices[0]) * count; 1008 return count; 1009} 1010 1011int SkPictureRecord::paints(size_t* size) const { 1012 size_t result = 0; 1013 int count = fPaints.count(); 1014 for (int index = 0; index < count; index++) 1015 result += sizeof(fPaints[index]) + fPaints[index]->size(); 1016 *size = result; 1017 return count; 1018} 1019 1020int SkPictureRecord::paths(size_t* size) const { 1021 size_t result = 0; 1022 int count = fPaths.count(); 1023 for (int index = 0; index < count; index++) 1024 result += sizeof(fPaths[index]) + fPaths[index]->size(); 1025 *size = result; 1026 return count; 1027} 1028 1029int SkPictureRecord::regions(size_t* size) const { 1030 size_t result = 0; 1031 int count = fRegions.count(); 1032 for (int index = 0; index < count; index++) 1033 result += sizeof(fRegions[index]) + fRegions[index]->size(); 1034 *size = result; 1035 return count; 1036} 1037 1038size_t SkPictureRecord::streamlen() const { 1039 return fWriter.size(); 1040} 1041#endif 1042 1043#ifdef SK_DEBUG_VALIDATE 1044void SkPictureRecord::validate(uint32_t initialOffset, uint32_t size) const { 1045 SkASSERT(fWriter.size() == initialOffset + size); 1046 1047 validateBitmaps(); 1048 validateMatrices(); 1049 validatePaints(); 1050 validatePaths(); 1051 validateRegions(); 1052} 1053 1054void SkPictureRecord::validateBitmaps() const { 1055 int count = fBitmapHeap->count(); 1056 SkASSERT((unsigned) count < 0x1000); 1057 for (int index = 0; index < count; index++) { 1058 const SkBitmap* bitPtr = fBitmapHeap->getBitmap(index); 1059 SkASSERT(bitPtr); 1060 bitPtr->validate(); 1061 } 1062} 1063 1064void SkPictureRecord::validateMatrices() const { 1065 int count = fMatrices.count(); 1066 SkASSERT((unsigned) count < 0x1000); 1067 for (int index = 0; index < count; index++) { 1068 const SkFlatData* matrix = fMatrices[index]; 1069 SkASSERT(matrix); 1070// matrix->validate(); 1071 } 1072} 1073 1074void SkPictureRecord::validatePaints() const { 1075 int count = fPaints.count(); 1076 SkASSERT((unsigned) count < 0x1000); 1077 for (int index = 0; index < count; index++) { 1078 const SkFlatData* paint = fPaints[index]; 1079 SkASSERT(paint); 1080// paint->validate(); 1081 } 1082} 1083 1084void SkPictureRecord::validatePaths() const { 1085 if (NULL == fPathHeap) { 1086 return; 1087 } 1088 1089 int count = fPathHeap->count(); 1090 SkASSERT((unsigned) count < 0x1000); 1091 for (int index = 0; index < count; index++) { 1092 const SkPath& path = (*fPathHeap)[index]; 1093 path.validate(); 1094 } 1095} 1096 1097void SkPictureRecord::validateRegions() const { 1098 int count = fRegions.count(); 1099 SkASSERT((unsigned) count < 0x1000); 1100 for (int index = 0; index < count; index++) { 1101 const SkFlatData* region = fRegions[index]; 1102 SkASSERT(region); 1103// region->validate(); 1104 } 1105} 1106#endif 1107