SkPictureRecord.cpp revision 2ff1fcede1e9525285c5de1f35fb2dcb0fab32bd
1/* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkPictureRecord.h" 9#include "SkDevice.h" 10#include "SkPatchUtils.h" 11#include "SkPixelRef.h" 12#include "SkRRect.h" 13#include "SkTextBlob.h" 14#include "SkTSearch.h" 15 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 kSaveSize = kUInt32Size; 27#ifdef SK_DEBUG 28static const uint32_t kSaveLayerNoBoundsSize = 4 * kUInt32Size; 29static const uint32_t kSaveLayerWithBoundsSize = 4 * kUInt32Size + sizeof(SkRect); 30#endif//SK_DEBUG 31 32SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) 33 : INHERITED(dimensions.width(), dimensions.height()) 34 , fFirstSavedLayerIndex(kNoSavedLayerIndex) 35 , fRecordFlags(flags) 36 , fInitialSaveCount(kNoInitialSave) { 37} 38 39SkPictureRecord::~SkPictureRecord() { 40 fPictureRefs.unrefAll(); 41 fTextBlobRefs.unrefAll(); 42} 43 44/////////////////////////////////////////////////////////////////////////////// 45 46#ifdef SK_DEBUG 47// Return the offset of the paint inside a given op's byte stream. A zero 48// return value means there is no paint (and you really shouldn't be calling 49// this method) 50static inline size_t get_paint_offset(DrawType op, size_t opSize) { 51 // These offsets are where the paint would be if the op size doesn't overflow 52 static const uint8_t gPaintOffsets[] = { 53 0, // UNUSED - no paint 54 0, // CLIP_PATH - no paint 55 0, // CLIP_REGION - no paint 56 0, // CLIP_RECT - no paint 57 0, // CLIP_RRECT - no paint 58 0, // CONCAT - no paint 59 1, // DRAW_BITMAP - right after op code 60 1, // DRAW_BITMAP_MATRIX - right after op code, deprecated 61 1, // DRAW_BITMAP_NINE - right after op code 62 1, // DRAW_BITMAP_RECT_TO_RECT - right after op code 63 0, // DRAW_CLEAR - no paint 64 0, // DRAW_DATA - no paint 65 1, // DRAW_OVAL - right after op code 66 1, // DRAW_PAINT - right after op code 67 1, // DRAW_PATH - right after op code 68 0, // DRAW_PICTURE - no paint 69 1, // DRAW_POINTS - right after op code 70 1, // DRAW_POS_TEXT - right after op code 71 1, // DRAW_POS_TEXT_TOP_BOTTOM - right after op code 72 1, // DRAW_POS_TEXT_H - right after op code 73 1, // DRAW_POS_TEXT_H_TOP_BOTTOM - right after op code 74 1, // DRAW_RECT - right after op code 75 1, // DRAW_RRECT - right after op code 76 1, // DRAW_SPRITE - right after op code 77 1, // DRAW_TEXT - right after op code 78 1, // DRAW_TEXT_ON_PATH - right after op code 79 1, // DRAW_TEXT_TOP_BOTTOM - right after op code 80 1, // DRAW_VERTICES - right after op code 81 0, // RESTORE - no paint 82 0, // ROTATE - no paint 83 0, // SAVE - no paint 84 0, // SAVE_LAYER - see below - this paint's location varies 85 0, // SCALE - no paint 86 0, // SET_MATRIX - no paint 87 0, // SKEW - no paint 88 0, // TRANSLATE - no paint 89 0, // NOOP - no paint 90 0, // BEGIN_GROUP - no paint 91 0, // COMMENT - no paint 92 0, // END_GROUP - no paint 93 1, // DRAWDRRECT - right after op code 94 0, // PUSH_CULL - no paint 95 0, // POP_CULL - no paint 96 1, // DRAW_PATCH - right after op code 97 1, // DRAW_PICTURE_MATRIX_PAINT - right after op code 98 1, // DRAW_TEXT_BLOB- right after op code 99 }; 100 101 SK_COMPILE_ASSERT(sizeof(gPaintOffsets) == LAST_DRAWTYPE_ENUM + 1, 102 need_to_be_in_sync); 103 SkASSERT((unsigned)op <= (unsigned)LAST_DRAWTYPE_ENUM); 104 105 int overflow = 0; 106 if (0 != (opSize & ~MASK_24) || opSize == MASK_24) { 107 // This op's size overflows so an extra uint32_t will be written 108 // after the op code 109 overflow = sizeof(uint32_t); 110 } 111 112 if (SAVE_LAYER == op) { 113 static const uint32_t kSaveLayerNoBoundsPaintOffset = 2 * kUInt32Size; 114 static const uint32_t kSaveLayerWithBoundsPaintOffset = 2 * kUInt32Size + sizeof(SkRect); 115 116 if (kSaveLayerNoBoundsSize == opSize) { 117 return kSaveLayerNoBoundsPaintOffset + overflow; 118 } else { 119 SkASSERT(kSaveLayerWithBoundsSize == opSize); 120 return kSaveLayerWithBoundsPaintOffset + overflow; 121 } 122 } 123 124 SkASSERT(0 != gPaintOffsets[op]); // really shouldn't be calling this method 125 return gPaintOffsets[op] * sizeof(uint32_t) + overflow; 126} 127#endif//SK_DEBUG 128 129void SkPictureRecord::willSave() { 130 // record the offset to us, making it non-positive to distinguish a save 131 // from a clip entry. 132 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); 133 this->recordSave(); 134 135 this->INHERITED::willSave(); 136} 137 138void SkPictureRecord::recordSave() { 139 fContentInfo.onSave(); 140 141 // op only 142 size_t size = kSaveSize; 143 size_t initialOffset = this->addDraw(SAVE, &size); 144 145 this->validate(initialOffset, size); 146} 147 148SkCanvas::SaveLayerStrategy SkPictureRecord::willSaveLayer(const SkRect* bounds, 149 const SkPaint* paint, SaveFlags flags) { 150 // record the offset to us, making it non-positive to distinguish a save 151 // from a clip entry. 152 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); 153 this->recordSaveLayer(bounds, paint, flags); 154 if (kNoSavedLayerIndex == fFirstSavedLayerIndex) { 155 fFirstSavedLayerIndex = fRestoreOffsetStack.count(); 156 } 157 158 this->INHERITED::willSaveLayer(bounds, paint, flags); 159 /* No need for a (potentially very big) layer which we don't actually need 160 at this time (and may not be able to afford since during record our 161 clip starts out the size of the picture, which is often much larger 162 than the size of the actual device we'll use during playback). 163 */ 164 return kNoLayer_SaveLayerStrategy; 165} 166 167void SkPictureRecord::recordSaveLayer(const SkRect* bounds, const SkPaint* paint, 168 SaveFlags flags) { 169 fContentInfo.onSaveLayer(); 170 171 // op + bool for 'bounds' 172 size_t size = 2 * kUInt32Size; 173 if (bounds) { 174 size += sizeof(*bounds); // + rect 175 } 176 // + paint index + flags 177 size += 2 * kUInt32Size; 178 179 SkASSERT(kSaveLayerNoBoundsSize == size || kSaveLayerWithBoundsSize == size); 180 181 size_t initialOffset = this->addDraw(SAVE_LAYER, &size); 182 this->addRectPtr(bounds); 183 SkASSERT(initialOffset+get_paint_offset(SAVE_LAYER, size) == fWriter.bytesWritten()); 184 this->addPaintPtr(paint); 185 this->addInt(flags); 186 187 this->validate(initialOffset, size); 188} 189 190bool SkPictureRecord::isDrawingToLayer() const { 191 return fFirstSavedLayerIndex != kNoSavedLayerIndex; 192} 193 194#ifdef SK_DEBUG 195/* 196 * Read the op code from 'offset' in 'writer' and extract the size too. 197 */ 198static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) { 199 uint32_t peek = writer->readTAt<uint32_t>(offset); 200 201 uint32_t op; 202 UNPACK_8_24(peek, op, *size); 203 if (MASK_24 == *size) { 204 // size required its own slot right after the op code 205 *size = writer->readTAt<uint32_t>(offset + kUInt32Size); 206 } 207 return (DrawType) op; 208} 209#endif//SK_DEBUG 210 211void SkPictureRecord::willRestore() { 212 // FIXME: SkDeferredCanvas needs to be refactored to respect 213 // save/restore balancing so that the following test can be 214 // turned on permanently. 215#if 0 216 SkASSERT(fRestoreOffsetStack.count() > 1); 217#endif 218 219 // check for underflow 220 if (fRestoreOffsetStack.count() == 0) { 221 return; 222 } 223 224 if (fRestoreOffsetStack.count() == fFirstSavedLayerIndex) { 225 fFirstSavedLayerIndex = kNoSavedLayerIndex; 226 } 227 228 this->recordRestore(); 229 230 fRestoreOffsetStack.pop(); 231 232 this->INHERITED::willRestore(); 233} 234 235void SkPictureRecord::recordRestore(bool fillInSkips) { 236 fContentInfo.onRestore(); 237 238 if (fillInSkips) { 239 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten()); 240 } 241 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code 242 size_t initialOffset = this->addDraw(RESTORE, &size); 243 this->validate(initialOffset, size); 244} 245 246void SkPictureRecord::recordTranslate(const SkMatrix& m) { 247 SkASSERT(SkMatrix::kTranslate_Mask == m.getType()); 248 249 // op + dx + dy 250 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 251 size_t initialOffset = this->addDraw(TRANSLATE, &size); 252 this->addScalar(m.getTranslateX()); 253 this->addScalar(m.getTranslateY()); 254 this->validate(initialOffset, size); 255} 256 257void SkPictureRecord::recordScale(const SkMatrix& m) { 258 SkASSERT(SkMatrix::kScale_Mask == m.getType()); 259 260 // op + sx + sy 261 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 262 size_t initialOffset = this->addDraw(SCALE, &size); 263 this->addScalar(m.getScaleX()); 264 this->addScalar(m.getScaleY()); 265 this->validate(initialOffset, size); 266} 267 268void SkPictureRecord::didConcat(const SkMatrix& matrix) { 269 switch (matrix.getType()) { 270 case SkMatrix::kTranslate_Mask: 271 this->recordTranslate(matrix); 272 break; 273 case SkMatrix::kScale_Mask: 274 this->recordScale(matrix); 275 break; 276 default: 277 this->recordConcat(matrix); 278 break; 279 } 280 this->INHERITED::didConcat(matrix); 281} 282 283void SkPictureRecord::recordConcat(const SkMatrix& matrix) { 284 this->validate(fWriter.bytesWritten(), 0); 285 // op + matrix 286 size_t size = kUInt32Size + matrix.writeToMemory(NULL); 287 size_t initialOffset = this->addDraw(CONCAT, &size); 288 this->addMatrix(matrix); 289 this->validate(initialOffset, size); 290} 291 292void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) { 293 this->validate(fWriter.bytesWritten(), 0); 294 // op + matrix 295 size_t size = kUInt32Size + matrix.writeToMemory(NULL); 296 size_t initialOffset = this->addDraw(SET_MATRIX, &size); 297 this->addMatrix(matrix); 298 this->validate(initialOffset, size); 299 this->INHERITED::didSetMatrix(matrix); 300} 301 302static bool regionOpExpands(SkRegion::Op op) { 303 switch (op) { 304 case SkRegion::kUnion_Op: 305 case SkRegion::kXOR_Op: 306 case SkRegion::kReverseDifference_Op: 307 case SkRegion::kReplace_Op: 308 return true; 309 case SkRegion::kIntersect_Op: 310 case SkRegion::kDifference_Op: 311 return false; 312 default: 313 SkDEBUGFAIL("unknown region op"); 314 return false; 315 } 316} 317 318void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { 319 int32_t offset = fRestoreOffsetStack.top(); 320 while (offset > 0) { 321 uint32_t peek = fWriter.readTAt<uint32_t>(offset); 322 fWriter.overwriteTAt(offset, restoreOffset); 323 offset = peek; 324 } 325 326#ifdef SK_DEBUG 327 // offset of 0 has been disabled, so we skip it 328 if (offset > 0) { 329 // assert that the final offset value points to a save verb 330 uint32_t opSize; 331 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); 332 SkASSERT(SAVE == drawOp || SAVE_LAYER == drawOp); 333 } 334#endif 335} 336 337void SkPictureRecord::beginRecording() { 338 // we have to call this *after* our constructor, to ensure that it gets 339 // recorded. This is balanced by restoreToCount() call from endRecording, 340 // which in-turn calls our overridden restore(), so those get recorded too. 341 fInitialSaveCount = this->save(); 342} 343 344void SkPictureRecord::endRecording() { 345 SkASSERT(kNoInitialSave != fInitialSaveCount); 346 this->restoreToCount(fInitialSaveCount); 347} 348 349size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkRegion::Op op) { 350 if (fRestoreOffsetStack.isEmpty()) { 351 return -1; 352 } 353 354 // The RestoreOffset field is initially filled with a placeholder 355 // value that points to the offset of the previous RestoreOffset 356 // in the current stack level, thus forming a linked list so that 357 // the restore offsets can be filled in when the corresponding 358 // restore command is recorded. 359 int32_t prevOffset = fRestoreOffsetStack.top(); 360 361 if (regionOpExpands(op)) { 362 // Run back through any previous clip ops, and mark their offset to 363 // be 0, disabling their ability to trigger a jump-to-restore, otherwise 364 // they could hide this clips ability to expand the clip (i.e. go from 365 // empty to non-empty). 366 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0); 367 368 // Reset the pointer back to the previous clip so that subsequent 369 // restores don't overwrite the offsets we just cleared. 370 prevOffset = 0; 371 } 372 373 size_t offset = fWriter.bytesWritten(); 374 this->addInt(prevOffset); 375 fRestoreOffsetStack.top() = SkToU32(offset); 376 return offset; 377} 378 379void SkPictureRecord::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 380 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); 381 this->INHERITED::onClipRect(rect, op, edgeStyle); 382} 383 384size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkRegion::Op op, bool doAA) { 385 // id + rect + clip params 386 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; 387 // recordRestoreOffsetPlaceholder doesn't always write an offset 388 if (!fRestoreOffsetStack.isEmpty()) { 389 // + restore offset 390 size += kUInt32Size; 391 } 392 size_t initialOffset = this->addDraw(CLIP_RECT, &size); 393 this->addRect(rect); 394 this->addInt(ClipParams_pack(op, doAA)); 395 size_t offset = this->recordRestoreOffsetPlaceholder(op); 396 397 this->validate(initialOffset, size); 398 return offset; 399} 400 401void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 402 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); 403 this->INHERITED::onClipRRect(rrect, op, edgeStyle); 404} 405 406size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 407 // op + rrect + clip params 408 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; 409 // recordRestoreOffsetPlaceholder doesn't always write an offset 410 if (!fRestoreOffsetStack.isEmpty()) { 411 // + restore offset 412 size += kUInt32Size; 413 } 414 size_t initialOffset = this->addDraw(CLIP_RRECT, &size); 415 this->addRRect(rrect); 416 this->addInt(ClipParams_pack(op, doAA)); 417 size_t offset = recordRestoreOffsetPlaceholder(op); 418 this->validate(initialOffset, size); 419 return offset; 420} 421 422void SkPictureRecord::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 423 int pathID = this->addPathToHeap(path); 424 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle); 425 this->INHERITED::onClipPath(path, op, edgeStyle); 426} 427 428size_t SkPictureRecord::recordClipPath(int pathID, SkRegion::Op op, bool doAA) { 429 // op + path index + clip params 430 size_t size = 3 * kUInt32Size; 431 // recordRestoreOffsetPlaceholder doesn't always write an offset 432 if (!fRestoreOffsetStack.isEmpty()) { 433 // + restore offset 434 size += kUInt32Size; 435 } 436 size_t initialOffset = this->addDraw(CLIP_PATH, &size); 437 this->addInt(pathID); 438 this->addInt(ClipParams_pack(op, doAA)); 439 size_t offset = recordRestoreOffsetPlaceholder(op); 440 this->validate(initialOffset, size); 441 return offset; 442} 443 444void SkPictureRecord::onClipRegion(const SkRegion& region, SkRegion::Op op) { 445 this->recordClipRegion(region, op); 446 this->INHERITED::onClipRegion(region, op); 447} 448 449size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkRegion::Op op) { 450 // op + clip params + region 451 size_t size = 2 * kUInt32Size + region.writeToMemory(NULL); 452 // recordRestoreOffsetPlaceholder doesn't always write an offset 453 if (!fRestoreOffsetStack.isEmpty()) { 454 // + restore offset 455 size += kUInt32Size; 456 } 457 size_t initialOffset = this->addDraw(CLIP_REGION, &size); 458 this->addRegion(region); 459 this->addInt(ClipParams_pack(op, false)); 460 size_t offset = this->recordRestoreOffsetPlaceholder(op); 461 462 this->validate(initialOffset, size); 463 return offset; 464} 465 466void SkPictureRecord::drawPaint(const SkPaint& paint) { 467 // op + paint index 468 size_t size = 2 * kUInt32Size; 469 size_t initialOffset = this->addDraw(DRAW_PAINT, &size); 470 SkASSERT(initialOffset+get_paint_offset(DRAW_PAINT, size) == fWriter.bytesWritten()); 471 this->addPaint(paint); 472 this->validate(initialOffset, size); 473} 474 475void SkPictureRecord::drawPoints(PointMode mode, size_t count, const SkPoint pts[], 476 const SkPaint& paint) { 477 fContentInfo.onDrawPoints(count, paint); 478 479 // op + paint index + mode + count + point data 480 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint); 481 size_t initialOffset = this->addDraw(DRAW_POINTS, &size); 482 SkASSERT(initialOffset+get_paint_offset(DRAW_POINTS, size) == fWriter.bytesWritten()); 483 this->addPaint(paint); 484 485 this->addInt(mode); 486 this->addInt(SkToInt(count)); 487 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 488 this->validate(initialOffset, size); 489} 490 491void SkPictureRecord::drawOval(const SkRect& oval, const SkPaint& paint) { 492 // op + paint index + rect 493 size_t size = 2 * kUInt32Size + sizeof(oval); 494 size_t initialOffset = this->addDraw(DRAW_OVAL, &size); 495 SkASSERT(initialOffset+get_paint_offset(DRAW_OVAL, size) == fWriter.bytesWritten()); 496 this->addPaint(paint); 497 this->addRect(oval); 498 this->validate(initialOffset, size); 499} 500 501void SkPictureRecord::drawRect(const SkRect& rect, const SkPaint& paint) { 502 // op + paint index + rect 503 size_t size = 2 * kUInt32Size + sizeof(rect); 504 size_t initialOffset = this->addDraw(DRAW_RECT, &size); 505 SkASSERT(initialOffset+get_paint_offset(DRAW_RECT, size) == fWriter.bytesWritten()); 506 this->addPaint(paint); 507 this->addRect(rect); 508 this->validate(initialOffset, size); 509} 510 511void SkPictureRecord::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 512 // op + paint index + rrect 513 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory; 514 size_t initialOffset = this->addDraw(DRAW_RRECT, &size); 515 SkASSERT(initialOffset+get_paint_offset(DRAW_RRECT, size) == fWriter.bytesWritten()); 516 this->addPaint(paint); 517 this->addRRect(rrect); 518 this->validate(initialOffset, size); 519} 520 521void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 522 const SkPaint& paint) { 523 // op + paint index + rrects 524 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; 525 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size); 526 SkASSERT(initialOffset+get_paint_offset(DRAW_DRRECT, size) == fWriter.bytesWritten()); 527 this->addPaint(paint); 528 this->addRRect(outer); 529 this->addRRect(inner); 530 this->validate(initialOffset, size); 531} 532 533void SkPictureRecord::drawPath(const SkPath& path, const SkPaint& paint) { 534 fContentInfo.onDrawPath(path, paint); 535 536 // op + paint index + path index 537 size_t size = 3 * kUInt32Size; 538 size_t initialOffset = this->addDraw(DRAW_PATH, &size); 539 SkASSERT(initialOffset+get_paint_offset(DRAW_PATH, size) == fWriter.bytesWritten()); 540 this->addPaint(paint); 541 this->addPath(path); 542 this->validate(initialOffset, size); 543} 544 545void SkPictureRecord::drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, 546 const SkPaint* paint = NULL) { 547 // op + paint index + bitmap index + left + top 548 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 549 size_t initialOffset = this->addDraw(DRAW_BITMAP, &size); 550 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP, size) == fWriter.bytesWritten()); 551 this->addPaintPtr(paint); 552 this->addBitmap(bitmap); 553 this->addScalar(left); 554 this->addScalar(top); 555 this->validate(initialOffset, size); 556} 557 558void SkPictureRecord::drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, 559 const SkRect& dst, const SkPaint* paint, 560 DrawBitmapRectFlags flags) { 561 // id + paint index + bitmap index + bool for 'src' + flags 562 size_t size = 5 * kUInt32Size; 563 if (src) { 564 size += sizeof(*src); // + rect 565 } 566 size += sizeof(dst); // + rect 567 568 size_t initialOffset = this->addDraw(DRAW_BITMAP_RECT_TO_RECT, &size); 569 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_RECT_TO_RECT, size) 570 == fWriter.bytesWritten()); 571 this->addPaintPtr(paint); 572 this->addBitmap(bitmap); 573 this->addRectPtr(src); // may be null 574 this->addRect(dst); 575 this->addInt(flags); 576 this->validate(initialOffset, size); 577} 578 579void SkPictureRecord::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 580 const SkRect& dst, const SkPaint* paint) { 581 // op + paint index + bitmap id + center + dst rect 582 size_t size = 3 * kUInt32Size + sizeof(center) + sizeof(dst); 583 size_t initialOffset = this->addDraw(DRAW_BITMAP_NINE, &size); 584 SkASSERT(initialOffset+get_paint_offset(DRAW_BITMAP_NINE, size) == fWriter.bytesWritten()); 585 this->addPaintPtr(paint); 586 this->addBitmap(bitmap); 587 this->addIRect(center); 588 this->addRect(dst); 589 this->validate(initialOffset, size); 590} 591 592void SkPictureRecord::drawSprite(const SkBitmap& bitmap, int left, int top, 593 const SkPaint* paint = NULL) { 594 // op + paint index + bitmap index + left + top 595 size_t size = 5 * kUInt32Size; 596 size_t initialOffset = this->addDraw(DRAW_SPRITE, &size); 597 SkASSERT(initialOffset+get_paint_offset(DRAW_SPRITE, size) == fWriter.bytesWritten()); 598 this->addPaintPtr(paint); 599 this->addBitmap(bitmap); 600 this->addInt(left); 601 this->addInt(top); 602 this->validate(initialOffset, size); 603} 604 605void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 606 const SkPaint& paint) { 607 // op + paint index + length + 'length' worth of chars + x + y 608 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); 609 610 DrawType op = DRAW_TEXT; 611 size_t initialOffset = this->addDraw(op, &size); 612 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten()); 613 this->addPaint(paint); 614 this->addText(text, byteLength); 615 this->addScalar(x); 616 this->addScalar(y); 617 this->validate(initialOffset, size); 618} 619 620void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], 621 const SkPaint& paint) { 622 int points = paint.countText(text, byteLength); 623 624 // op + paint index + length + 'length' worth of data + num points + x&y point data 625 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint); 626 627 DrawType op = DRAW_POS_TEXT; 628 629 size_t initialOffset = this->addDraw(op, &size); 630 SkASSERT(initialOffset+get_paint_offset(op, size) == fWriter.bytesWritten()); 631 this->addPaint(paint); 632 this->addText(text, byteLength); 633 this->addInt(points); 634 fWriter.writeMul4(pos, points * sizeof(SkPoint)); 635 this->validate(initialOffset, size); 636} 637 638void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 639 SkScalar constY, const SkPaint& paint) { 640 int points = paint.countText(text, byteLength); 641 642 // op + paint index + length + 'length' worth of data + num points 643 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 644 // + y + the actual points 645 size += 1 * kUInt32Size + points * sizeof(SkScalar); 646 647 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size); 648 this->addPaint(paint); 649 this->addText(text, byteLength); 650 this->addInt(points); 651 this->addScalar(constY); 652 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); 653 this->validate(initialOffset, size); 654} 655 656void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 657 const SkMatrix* matrix, const SkPaint& paint) { 658 // op + paint index + length + 'length' worth of data + path index + matrix 659 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); 660 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(NULL); 661 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); 662 SkASSERT(initialOffset+get_paint_offset(DRAW_TEXT_ON_PATH, size) == fWriter.bytesWritten()); 663 this->addPaint(paint); 664 this->addText(text, byteLength); 665 this->addPath(path); 666 this->addMatrix(m); 667 this->validate(initialOffset, size); 668} 669 670void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 671 const SkPaint& paint) { 672 673 // op + paint index + blob index + x/y 674 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 675 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size); 676 SkASSERT(initialOffset + get_paint_offset(DRAW_TEXT_BLOB, size) == fWriter.bytesWritten()); 677 678 this->addPaint(paint); 679 this->addTextBlob(blob); 680 this->addScalar(x); 681 this->addScalar(y); 682 683 this->validate(initialOffset, size); 684} 685 686void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 687 const SkPaint* paint) { 688 // op + picture index 689 size_t size = 2 * kUInt32Size; 690 size_t initialOffset; 691 692 if (NULL == matrix && NULL == paint) { 693 initialOffset = this->addDraw(DRAW_PICTURE, &size); 694 this->addPicture(picture); 695 } else { 696 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); 697 size += m.writeToMemory(NULL) + kUInt32Size; // matrix + paint 698 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size); 699 SkASSERT(initialOffset + get_paint_offset(DRAW_PICTURE_MATRIX_PAINT, size) 700 == fWriter.bytesWritten()); 701 this->addPaintPtr(paint); 702 this->addMatrix(m); 703 this->addPicture(picture); 704 } 705 this->validate(initialOffset, size); 706} 707 708void SkPictureRecord::drawVertices(VertexMode vmode, int vertexCount, 709 const SkPoint vertices[], const SkPoint texs[], 710 const SkColor colors[], SkXfermode* xfer, 711 const uint16_t indices[], int indexCount, 712 const SkPaint& paint) { 713 uint32_t flags = 0; 714 if (texs) { 715 flags |= DRAW_VERTICES_HAS_TEXS; 716 } 717 if (colors) { 718 flags |= DRAW_VERTICES_HAS_COLORS; 719 } 720 if (indexCount > 0) { 721 flags |= DRAW_VERTICES_HAS_INDICES; 722 } 723 if (xfer) { 724 SkXfermode::Mode mode; 725 if (xfer->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { 726 flags |= DRAW_VERTICES_HAS_XFER; 727 } 728 } 729 730 // op + paint index + flags + vmode + vCount + vertices 731 size_t size = 5 * kUInt32Size + vertexCount * sizeof(SkPoint); 732 if (flags & DRAW_VERTICES_HAS_TEXS) { 733 size += vertexCount * sizeof(SkPoint); // + uvs 734 } 735 if (flags & DRAW_VERTICES_HAS_COLORS) { 736 size += vertexCount * sizeof(SkColor); // + vert colors 737 } 738 if (flags & DRAW_VERTICES_HAS_INDICES) { 739 // + num indices + indices 740 size += 1 * kUInt32Size + SkAlign4(indexCount * sizeof(uint16_t)); 741 } 742 if (flags & DRAW_VERTICES_HAS_XFER) { 743 size += kUInt32Size; // mode enum 744 } 745 746 size_t initialOffset = this->addDraw(DRAW_VERTICES, &size); 747 SkASSERT(initialOffset+get_paint_offset(DRAW_VERTICES, size) == fWriter.bytesWritten()); 748 this->addPaint(paint); 749 this->addInt(flags); 750 this->addInt(vmode); 751 this->addInt(vertexCount); 752 this->addPoints(vertices, vertexCount); 753 if (flags & DRAW_VERTICES_HAS_TEXS) { 754 this->addPoints(texs, vertexCount); 755 } 756 if (flags & DRAW_VERTICES_HAS_COLORS) { 757 fWriter.writeMul4(colors, vertexCount * sizeof(SkColor)); 758 } 759 if (flags & DRAW_VERTICES_HAS_INDICES) { 760 this->addInt(indexCount); 761 fWriter.writePad(indices, indexCount * sizeof(uint16_t)); 762 } 763 if (flags & DRAW_VERTICES_HAS_XFER) { 764 SkXfermode::Mode mode = SkXfermode::kModulate_Mode; 765 (void)xfer->asMode(&mode); 766 this->addInt(mode); 767 } 768 this->validate(initialOffset, size); 769} 770 771void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 772 const SkPoint texCoords[4], SkXfermode* xmode, 773 const SkPaint& paint) { 774 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates 775 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size; 776 uint32_t flag = 0; 777 if (colors) { 778 flag |= DRAW_VERTICES_HAS_COLORS; 779 size += SkPatchUtils::kNumCorners * sizeof(SkColor); 780 } 781 if (texCoords) { 782 flag |= DRAW_VERTICES_HAS_TEXS; 783 size += SkPatchUtils::kNumCorners * sizeof(SkPoint); 784 } 785 if (xmode) { 786 SkXfermode::Mode mode; 787 if (xmode->asMode(&mode) && SkXfermode::kModulate_Mode != mode) { 788 flag |= DRAW_VERTICES_HAS_XFER; 789 size += kUInt32Size; 790 } 791 } 792 793 size_t initialOffset = this->addDraw(DRAW_PATCH, &size); 794 SkASSERT(initialOffset+get_paint_offset(DRAW_PATCH, size) == fWriter.bytesWritten()); 795 this->addPaint(paint); 796 this->addPatch(cubics); 797 this->addInt(flag); 798 799 // write optional parameters 800 if (colors) { 801 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor)); 802 } 803 if (texCoords) { 804 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint)); 805 } 806 if (flag & DRAW_VERTICES_HAS_XFER) { 807 SkXfermode::Mode mode = SkXfermode::kModulate_Mode; 808 xmode->asMode(&mode); 809 this->addInt(mode); 810 } 811 this->validate(initialOffset, size); 812} 813 814void SkPictureRecord::drawData(const void* data, size_t length) { 815 // op + length + 'length' worth of data 816 size_t size = 2 * kUInt32Size + SkAlign4(length); 817 size_t initialOffset = this->addDraw(DRAW_DATA, &size); 818 this->addInt(SkToInt(length)); 819 fWriter.writePad(data, length); 820 this->validate(initialOffset, size); 821} 822 823void SkPictureRecord::beginCommentGroup(const char* description) { 824 // op/size + length of string + \0 terminated chars 825 size_t length = strlen(description); 826 size_t size = 2 * kUInt32Size + SkAlign4(length + 1); 827 size_t initialOffset = this->addDraw(BEGIN_COMMENT_GROUP, &size); 828 fWriter.writeString(description, length); 829 this->validate(initialOffset, size); 830} 831 832void SkPictureRecord::addComment(const char* kywd, const char* value) { 833 // op/size + 2x length of string + 2x \0 terminated chars 834 size_t kywdLen = strlen(kywd); 835 size_t valueLen = strlen(value); 836 size_t size = 3 * kUInt32Size + SkAlign4(kywdLen + 1) + SkAlign4(valueLen + 1); 837 size_t initialOffset = this->addDraw(COMMENT, &size); 838 fWriter.writeString(kywd, kywdLen); 839 fWriter.writeString(value, valueLen); 840 this->validate(initialOffset, size); 841} 842 843void SkPictureRecord::endCommentGroup() { 844 // op/size 845 size_t size = 1 * kUInt32Size; 846 size_t initialOffset = this->addDraw(END_COMMENT_GROUP, &size); 847 this->validate(initialOffset, size); 848} 849 850// [op/size] [rect] [skip offset] 851static const uint32_t kPushCullOpSize = 2 * kUInt32Size + sizeof(SkRect); 852void SkPictureRecord::onPushCull(const SkRect& cullRect) { 853 size_t size = kPushCullOpSize; 854 size_t initialOffset = this->addDraw(PUSH_CULL, &size); 855 // PUSH_CULL's size should stay constant (used to rewind). 856 SkASSERT(size == kPushCullOpSize); 857 858 this->addRect(cullRect); 859 fCullOffsetStack.push(SkToU32(fWriter.bytesWritten())); 860 this->addInt(0); 861 this->validate(initialOffset, size); 862} 863 864void SkPictureRecord::onPopCull() { 865 SkASSERT(!fCullOffsetStack.isEmpty()); 866 867 uint32_t cullSkipOffset = fCullOffsetStack.top(); 868 fCullOffsetStack.pop(); 869 870 // op only 871 size_t size = kUInt32Size; 872 size_t initialOffset = this->addDraw(POP_CULL, &size); 873 874 // update the cull skip offset to point past this op. 875 fWriter.overwriteTAt<uint32_t>(cullSkipOffset, SkToU32(fWriter.bytesWritten())); 876 877 this->validate(initialOffset, size); 878} 879 880/////////////////////////////////////////////////////////////////////////////// 881 882SkSurface* SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) { 883 return NULL; 884} 885 886// If we already have a stored, can we reuse it instead of also storing b? 887static bool equivalent(const SkBitmap& a, const SkBitmap& b) { 888 if (a.info() != b.info() || a.pixelRefOrigin() != b.pixelRefOrigin()) { 889 // Requiring a.info() == b.info() may be overkill in some cases (alphatype mismatch), 890 // but it sure makes things easier to reason about below. 891 return false; 892 } 893 if (a.pixelRef() == b.pixelRef()) { 894 return true; // Same shape and same pixels -> same bitmap. 895 } 896 897 // From here down we're going to have to look at the bitmap data, so we require pixelRefs(). 898 if (!a.pixelRef() || !b.pixelRef()) { 899 return false; 900 } 901 902 // If the bitmaps have encoded data, check first before locking pixels so they don't decode. 903 SkAutoTUnref<SkData> encA(a.pixelRef()->refEncodedData()), 904 encB(b.pixelRef()->refEncodedData()); 905 if (encA && encB) { 906 return encA->equals(encB); 907 } else if (encA || encB) { 908 return false; // One has encoded data but the other does not. 909 } 910 911 // As a last resort, we have to look at the pixels. This will read back textures. 912 SkAutoLockPixels al(a), bl(b); 913 const char* ap = (const char*)a.getPixels(); 914 const char* bp = (const char*)b.getPixels(); 915 if (ap && bp) { 916 // We check row by row; row bytes might differ. 917 SkASSERT(a.info() == b.info()); // We checked this above. 918 SkASSERT(a.info().bytesPerPixel() > 0); // If we have pixelRefs, this better be true. 919 const SkImageInfo info = a.info(); 920 const size_t bytesToCompare = info.width() * info.bytesPerPixel(); 921 for (int row = 0; row < info.height(); row++) { 922 if (0 != memcmp(ap, bp, bytesToCompare)) { 923 return false; 924 } 925 ap += a.rowBytes(); 926 bp += b.rowBytes(); 927 } 928 return true; 929 } 930 return false; // Couldn't get pixels for both bitmaps. 931} 932 933void SkPictureRecord::addBitmap(const SkBitmap& bitmap) { 934 // First see if we already have this bitmap. This deduplication should really 935 // only be important for our tests, where bitmaps tend not to be tagged immutable. 936 // In Chrome (and hopefully Android?) they're typically immutable. 937 for (int i = 0; i < fBitmaps.count(); i++) { 938 if (equivalent(fBitmaps[i], bitmap)) { 939 this->addInt(i); // Unlike the rest, bitmap indices are 0-based. 940 return; 941 } 942 } 943 // Don't have it. We'll add it to our list, making sure it's tagged as immutable. 944 if (bitmap.isImmutable()) { 945 // Shallow copies of bitmaps are cheap, so immutable == fast. 946 fBitmaps.push_back(bitmap); 947 } else { 948 // If you see this block on a memory profile, it's a good opportunity to reduce RAM usage. 949 SkBitmap copy; 950 bitmap.copyTo(©); 951 copy.setImmutable(); 952 fBitmaps.push_back(copy); 953 } 954 this->addInt(fBitmaps.count()-1); // Remember, 0-based. 955} 956 957void SkPictureRecord::addMatrix(const SkMatrix& matrix) { 958 fWriter.writeMatrix(matrix); 959} 960 961void SkPictureRecord::addPaintPtr(const SkPaint* paint) { 962 fContentInfo.onAddPaintPtr(paint); 963 964 if (paint) { 965 fPaints.push_back(*paint); 966 this->addInt(fPaints.count()); 967 } else { 968 this->addInt(0); 969 } 970} 971 972int SkPictureRecord::addPathToHeap(const SkPath& path) { 973 fPaths.push_back(path); 974 return fPaths.count(); 975} 976 977void SkPictureRecord::addPath(const SkPath& path) { 978 this->addInt(this->addPathToHeap(path)); 979} 980 981void SkPictureRecord::addPatch(const SkPoint cubics[12]) { 982 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint)); 983} 984 985void SkPictureRecord::addPicture(const SkPicture* picture) { 986 int index = fPictureRefs.find(picture); 987 if (index < 0) { // not found 988 index = fPictureRefs.count(); 989 *fPictureRefs.append() = picture; 990 picture->ref(); 991 } 992 // follow the convention of recording a 1-based index 993 this->addInt(index + 1); 994} 995 996void SkPictureRecord::addPoint(const SkPoint& point) { 997 fWriter.writePoint(point); 998} 999 1000void SkPictureRecord::addPoints(const SkPoint pts[], int count) { 1001 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 1002} 1003 1004void SkPictureRecord::addNoOp() { 1005 size_t size = kUInt32Size; // op 1006 this->addDraw(NOOP, &size); 1007} 1008 1009void SkPictureRecord::addRect(const SkRect& rect) { 1010 fWriter.writeRect(rect); 1011} 1012 1013void SkPictureRecord::addRectPtr(const SkRect* rect) { 1014 if (fWriter.writeBool(rect != NULL)) { 1015 fWriter.writeRect(*rect); 1016 } 1017} 1018 1019void SkPictureRecord::addIRect(const SkIRect& rect) { 1020 fWriter.write(&rect, sizeof(rect)); 1021} 1022 1023void SkPictureRecord::addIRectPtr(const SkIRect* rect) { 1024 if (fWriter.writeBool(rect != NULL)) { 1025 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; 1026 } 1027} 1028 1029void SkPictureRecord::addRRect(const SkRRect& rrect) { 1030 fWriter.writeRRect(rrect); 1031} 1032 1033void SkPictureRecord::addRegion(const SkRegion& region) { 1034 fWriter.writeRegion(region); 1035} 1036 1037void SkPictureRecord::addText(const void* text, size_t byteLength) { 1038 fContentInfo.onDrawText(); 1039 addInt(SkToInt(byteLength)); 1040 fWriter.writePad(text, byteLength); 1041} 1042 1043void SkPictureRecord::addTextBlob(const SkTextBlob *blob) { 1044 int index = fTextBlobRefs.count(); 1045 *fTextBlobRefs.append() = blob; 1046 blob->ref(); 1047 // follow the convention of recording a 1-based index 1048 this->addInt(index + 1); 1049} 1050 1051/////////////////////////////////////////////////////////////////////////////// 1052 1053