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