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