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 "SkImage_Base.h" 10 #include "SkPatchUtils.h" 11 #include "SkPixelRef.h" 12 #include "SkRRect.h" 13 #include "SkRSXform.h" 14 #include "SkTextBlob.h" 15 #include "SkTSearch.h" 16 #include "SkClipOpPriv.h" 17 18 #define HEAP_BLOCK_SIZE 4096 19 20 enum { 21 // just need a value that save or getSaveCount would never return 22 kNoInitialSave = -1, 23 }; 24 25 // A lot of basic types get stored as a uint32_t: bools, ints, paint indices, etc. 26 static int const kUInt32Size = 4; 27 28 SkPictureRecord::SkPictureRecord(const SkISize& dimensions, uint32_t flags) 29 : INHERITED(dimensions.width(), dimensions.height()) 30 , fRecordFlags(flags) 31 , fInitialSaveCount(kNoInitialSave) { 32 } 33 34 SkPictureRecord::~SkPictureRecord() { 35 fImageRefs.unrefAll(); 36 fPictureRefs.unrefAll(); 37 fDrawableRefs.unrefAll(); 38 fTextBlobRefs.unrefAll(); 39 fVerticesRefs.unrefAll(); 40 } 41 42 /////////////////////////////////////////////////////////////////////////////// 43 44 void SkPictureRecord::willSave() { 45 // record the offset to us, making it non-positive to distinguish a save 46 // from a clip entry. 47 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); 48 this->recordSave(); 49 50 this->INHERITED::willSave(); 51 } 52 53 void SkPictureRecord::recordSave() { 54 fContentInfo.onSave(); 55 56 // op only 57 size_t size = sizeof(kUInt32Size); 58 size_t initialOffset = this->addDraw(SAVE, &size); 59 60 this->validate(initialOffset, size); 61 } 62 63 SkCanvas::SaveLayerStrategy SkPictureRecord::getSaveLayerStrategy(const SaveLayerRec& rec) { 64 // record the offset to us, making it non-positive to distinguish a save 65 // from a clip entry. 66 fRestoreOffsetStack.push(-(int32_t)fWriter.bytesWritten()); 67 this->recordSaveLayer(rec); 68 69 (void)this->INHERITED::getSaveLayerStrategy(rec); 70 /* No need for a (potentially very big) layer which we don't actually need 71 at this time (and may not be able to afford since during record our 72 clip starts out the size of the picture, which is often much larger 73 than the size of the actual device we'll use during playback). 74 */ 75 return kNoLayer_SaveLayerStrategy; 76 } 77 78 void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) { 79 fContentInfo.onSaveLayer(); 80 81 // op + flatflags 82 size_t size = 2 * kUInt32Size; 83 uint32_t flatFlags = 0; 84 85 if (rec.fBounds) { 86 flatFlags |= SAVELAYERREC_HAS_BOUNDS; 87 size += sizeof(*rec.fBounds); 88 } 89 if (rec.fPaint) { 90 flatFlags |= SAVELAYERREC_HAS_PAINT; 91 size += sizeof(uint32_t); // index 92 } 93 if (rec.fBackdrop) { 94 flatFlags |= SAVELAYERREC_HAS_BACKDROP; 95 size += sizeof(uint32_t); // (paint) index 96 } 97 if (rec.fSaveLayerFlags) { 98 flatFlags |= SAVELAYERREC_HAS_FLAGS; 99 size += sizeof(uint32_t); 100 } 101 102 const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size); 103 this->addInt(flatFlags); 104 if (flatFlags & SAVELAYERREC_HAS_BOUNDS) { 105 this->addRect(*rec.fBounds); 106 } 107 if (flatFlags & SAVELAYERREC_HAS_PAINT) { 108 this->addPaintPtr(rec.fPaint); 109 } 110 if (flatFlags & SAVELAYERREC_HAS_BACKDROP) { 111 // overkill, but we didn't already track single flattenables, so using a paint for that 112 SkPaint paint; 113 paint.setImageFilter(sk_ref_sp(const_cast<SkImageFilter*>(rec.fBackdrop))); 114 this->addPaint(paint); 115 } 116 if (flatFlags & SAVELAYERREC_HAS_FLAGS) { 117 this->addInt(rec.fSaveLayerFlags); 118 } 119 this->validate(initialOffset, size); 120 } 121 122 #ifdef SK_DEBUG 123 /* 124 * Read the op code from 'offset' in 'writer' and extract the size too. 125 */ 126 static DrawType peek_op_and_size(SkWriter32* writer, size_t offset, uint32_t* size) { 127 uint32_t peek = writer->readTAt<uint32_t>(offset); 128 129 uint32_t op; 130 UNPACK_8_24(peek, op, *size); 131 if (MASK_24 == *size) { 132 // size required its own slot right after the op code 133 *size = writer->readTAt<uint32_t>(offset + kUInt32Size); 134 } 135 return (DrawType) op; 136 } 137 #endif//SK_DEBUG 138 139 void SkPictureRecord::willRestore() { 140 #if 0 141 SkASSERT(fRestoreOffsetStack.count() > 1); 142 #endif 143 144 // check for underflow 145 if (fRestoreOffsetStack.count() == 0) { 146 return; 147 } 148 149 this->recordRestore(); 150 151 fRestoreOffsetStack.pop(); 152 153 this->INHERITED::willRestore(); 154 } 155 156 void SkPictureRecord::recordRestore(bool fillInSkips) { 157 fContentInfo.onRestore(); 158 159 if (fillInSkips) { 160 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel((uint32_t)fWriter.bytesWritten()); 161 } 162 size_t size = 1 * kUInt32Size; // RESTORE consists solely of 1 op code 163 size_t initialOffset = this->addDraw(RESTORE, &size); 164 this->validate(initialOffset, size); 165 } 166 167 void SkPictureRecord::recordTranslate(const SkMatrix& m) { 168 SkASSERT(SkMatrix::kTranslate_Mask == m.getType()); 169 170 // op + dx + dy 171 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 172 size_t initialOffset = this->addDraw(TRANSLATE, &size); 173 this->addScalar(m.getTranslateX()); 174 this->addScalar(m.getTranslateY()); 175 this->validate(initialOffset, size); 176 } 177 178 void SkPictureRecord::recordScale(const SkMatrix& m) { 179 SkASSERT(SkMatrix::kScale_Mask == m.getType()); 180 181 // op + sx + sy 182 size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar); 183 size_t initialOffset = this->addDraw(SCALE, &size); 184 this->addScalar(m.getScaleX()); 185 this->addScalar(m.getScaleY()); 186 this->validate(initialOffset, size); 187 } 188 189 void SkPictureRecord::didConcat(const SkMatrix& matrix) { 190 switch (matrix.getType()) { 191 case SkMatrix::kTranslate_Mask: 192 this->recordTranslate(matrix); 193 break; 194 case SkMatrix::kScale_Mask: 195 this->recordScale(matrix); 196 break; 197 default: 198 this->recordConcat(matrix); 199 break; 200 } 201 this->INHERITED::didConcat(matrix); 202 } 203 204 void SkPictureRecord::recordConcat(const SkMatrix& matrix) { 205 this->validate(fWriter.bytesWritten(), 0); 206 // op + matrix 207 size_t size = kUInt32Size + matrix.writeToMemory(nullptr); 208 size_t initialOffset = this->addDraw(CONCAT, &size); 209 this->addMatrix(matrix); 210 this->validate(initialOffset, size); 211 } 212 213 void SkPictureRecord::didSetMatrix(const SkMatrix& matrix) { 214 this->validate(fWriter.bytesWritten(), 0); 215 // op + matrix 216 size_t size = kUInt32Size + matrix.writeToMemory(nullptr); 217 size_t initialOffset = this->addDraw(SET_MATRIX, &size); 218 this->addMatrix(matrix); 219 this->validate(initialOffset, size); 220 this->INHERITED::didSetMatrix(matrix); 221 } 222 223 void SkPictureRecord::didTranslateZ(SkScalar z) { 224 #ifdef SK_EXPERIMENTAL_SHADOWING 225 this->validate(fWriter.bytesWritten(), 0); 226 // op + scalar 227 size_t size = 1 * kUInt32Size + 1 * sizeof(SkScalar); 228 size_t initialOffset = this->addDraw(TRANSLATE_Z, &size); 229 this->addScalar(z); 230 this->validate(initialOffset, size); 231 this->INHERITED::didTranslateZ(z); 232 #endif 233 } 234 235 static bool clipOpExpands(SkClipOp op) { 236 switch (op) { 237 case kUnion_SkClipOp: 238 case kXOR_SkClipOp: 239 case kReverseDifference_SkClipOp: 240 case kReplace_SkClipOp: 241 return true; 242 case kIntersect_SkClipOp: 243 case kDifference_SkClipOp: 244 return false; 245 default: 246 SkDEBUGFAIL("unknown clipop"); 247 return false; 248 } 249 } 250 251 void SkPictureRecord::fillRestoreOffsetPlaceholdersForCurrentStackLevel(uint32_t restoreOffset) { 252 int32_t offset = fRestoreOffsetStack.top(); 253 while (offset > 0) { 254 uint32_t peek = fWriter.readTAt<uint32_t>(offset); 255 fWriter.overwriteTAt(offset, restoreOffset); 256 offset = peek; 257 } 258 259 #ifdef SK_DEBUG 260 // offset of 0 has been disabled, so we skip it 261 if (offset > 0) { 262 // assert that the final offset value points to a save verb 263 uint32_t opSize; 264 DrawType drawOp = peek_op_and_size(&fWriter, -offset, &opSize); 265 SkASSERT(SAVE_LAYER_SAVEFLAGS_DEPRECATED != drawOp); 266 SkASSERT(SAVE_LAYER_SAVELAYERFLAGS_DEPRECATED_JAN_2016 != drawOp); 267 SkASSERT(SAVE == drawOp || SAVE_LAYER_SAVELAYERREC == drawOp); 268 } 269 #endif 270 } 271 272 void SkPictureRecord::beginRecording() { 273 // we have to call this *after* our constructor, to ensure that it gets 274 // recorded. This is balanced by restoreToCount() call from endRecording, 275 // which in-turn calls our overridden restore(), so those get recorded too. 276 fInitialSaveCount = this->save(); 277 } 278 279 void SkPictureRecord::endRecording() { 280 SkASSERT(kNoInitialSave != fInitialSaveCount); 281 this->restoreToCount(fInitialSaveCount); 282 } 283 284 size_t SkPictureRecord::recordRestoreOffsetPlaceholder(SkClipOp op) { 285 if (fRestoreOffsetStack.isEmpty()) { 286 return -1; 287 } 288 289 // The RestoreOffset field is initially filled with a placeholder 290 // value that points to the offset of the previous RestoreOffset 291 // in the current stack level, thus forming a linked list so that 292 // the restore offsets can be filled in when the corresponding 293 // restore command is recorded. 294 int32_t prevOffset = fRestoreOffsetStack.top(); 295 296 if (clipOpExpands(op)) { 297 // Run back through any previous clip ops, and mark their offset to 298 // be 0, disabling their ability to trigger a jump-to-restore, otherwise 299 // they could hide this clips ability to expand the clip (i.e. go from 300 // empty to non-empty). 301 this->fillRestoreOffsetPlaceholdersForCurrentStackLevel(0); 302 303 // Reset the pointer back to the previous clip so that subsequent 304 // restores don't overwrite the offsets we just cleared. 305 prevOffset = 0; 306 } 307 308 size_t offset = fWriter.bytesWritten(); 309 this->addInt(prevOffset); 310 fRestoreOffsetStack.top() = SkToU32(offset); 311 return offset; 312 } 313 314 void SkPictureRecord::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) { 315 this->recordClipRect(rect, op, kSoft_ClipEdgeStyle == edgeStyle); 316 this->INHERITED::onClipRect(rect, op, edgeStyle); 317 } 318 319 size_t SkPictureRecord::recordClipRect(const SkRect& rect, SkClipOp op, bool doAA) { 320 // id + rect + clip params 321 size_t size = 1 * kUInt32Size + sizeof(rect) + 1 * kUInt32Size; 322 // recordRestoreOffsetPlaceholder doesn't always write an offset 323 if (!fRestoreOffsetStack.isEmpty()) { 324 // + restore offset 325 size += kUInt32Size; 326 } 327 size_t initialOffset = this->addDraw(CLIP_RECT, &size); 328 this->addRect(rect); 329 this->addInt(ClipParams_pack(op, doAA)); 330 size_t offset = this->recordRestoreOffsetPlaceholder(op); 331 332 this->validate(initialOffset, size); 333 return offset; 334 } 335 336 void SkPictureRecord::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle) { 337 this->recordClipRRect(rrect, op, kSoft_ClipEdgeStyle == edgeStyle); 338 this->INHERITED::onClipRRect(rrect, op, edgeStyle); 339 } 340 341 size_t SkPictureRecord::recordClipRRect(const SkRRect& rrect, SkClipOp op, bool doAA) { 342 // op + rrect + clip params 343 size_t size = 1 * kUInt32Size + SkRRect::kSizeInMemory + 1 * kUInt32Size; 344 // recordRestoreOffsetPlaceholder doesn't always write an offset 345 if (!fRestoreOffsetStack.isEmpty()) { 346 // + restore offset 347 size += kUInt32Size; 348 } 349 size_t initialOffset = this->addDraw(CLIP_RRECT, &size); 350 this->addRRect(rrect); 351 this->addInt(ClipParams_pack(op, doAA)); 352 size_t offset = recordRestoreOffsetPlaceholder(op); 353 this->validate(initialOffset, size); 354 return offset; 355 } 356 357 void SkPictureRecord::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) { 358 int pathID = this->addPathToHeap(path); 359 this->recordClipPath(pathID, op, kSoft_ClipEdgeStyle == edgeStyle); 360 this->INHERITED::onClipPath(path, op, edgeStyle); 361 } 362 363 size_t SkPictureRecord::recordClipPath(int pathID, SkClipOp op, bool doAA) { 364 // op + path index + clip params 365 size_t size = 3 * kUInt32Size; 366 // recordRestoreOffsetPlaceholder doesn't always write an offset 367 if (!fRestoreOffsetStack.isEmpty()) { 368 // + restore offset 369 size += kUInt32Size; 370 } 371 size_t initialOffset = this->addDraw(CLIP_PATH, &size); 372 this->addInt(pathID); 373 this->addInt(ClipParams_pack(op, doAA)); 374 size_t offset = recordRestoreOffsetPlaceholder(op); 375 this->validate(initialOffset, size); 376 return offset; 377 } 378 379 void SkPictureRecord::onClipRegion(const SkRegion& region, SkClipOp op) { 380 this->recordClipRegion(region, op); 381 this->INHERITED::onClipRegion(region, op); 382 } 383 384 size_t SkPictureRecord::recordClipRegion(const SkRegion& region, SkClipOp op) { 385 // op + clip params + region 386 size_t size = 2 * kUInt32Size + region.writeToMemory(nullptr); 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_REGION, &size); 393 this->addRegion(region); 394 this->addInt(ClipParams_pack(op, false)); 395 size_t offset = this->recordRestoreOffsetPlaceholder(op); 396 397 this->validate(initialOffset, size); 398 return offset; 399 } 400 401 void SkPictureRecord::onDrawPaint(const SkPaint& paint) { 402 // op + paint index 403 size_t size = 2 * kUInt32Size; 404 size_t initialOffset = this->addDraw(DRAW_PAINT, &size); 405 this->addPaint(paint); 406 this->validate(initialOffset, size); 407 } 408 409 void SkPictureRecord::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], 410 const SkPaint& paint) { 411 fContentInfo.onDrawPoints(count, paint); 412 413 // op + paint index + mode + count + point data 414 size_t size = 4 * kUInt32Size + count * sizeof(SkPoint); 415 size_t initialOffset = this->addDraw(DRAW_POINTS, &size); 416 this->addPaint(paint); 417 418 this->addInt(mode); 419 this->addInt(SkToInt(count)); 420 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 421 this->validate(initialOffset, size); 422 } 423 424 void SkPictureRecord::onDrawOval(const SkRect& oval, const SkPaint& paint) { 425 // op + paint index + rect 426 size_t size = 2 * kUInt32Size + sizeof(oval); 427 size_t initialOffset = this->addDraw(DRAW_OVAL, &size); 428 this->addPaint(paint); 429 this->addRect(oval); 430 this->validate(initialOffset, size); 431 } 432 433 void SkPictureRecord::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 434 bool useCenter, const SkPaint& paint) { 435 // op + paint index + rect + start + sweep + bool (as int) 436 size_t size = 2 * kUInt32Size + sizeof(oval) + sizeof(startAngle) + sizeof(sweepAngle) + 437 sizeof(int); 438 size_t initialOffset = this->addDraw(DRAW_ARC, &size); 439 this->addPaint(paint); 440 this->addRect(oval); 441 this->addScalar(startAngle); 442 this->addScalar(sweepAngle); 443 this->addInt(useCenter); 444 this->validate(initialOffset, size); 445 } 446 447 void SkPictureRecord::onDrawRect(const SkRect& rect, const SkPaint& paint) { 448 // op + paint index + rect 449 size_t size = 2 * kUInt32Size + sizeof(rect); 450 size_t initialOffset = this->addDraw(DRAW_RECT, &size); 451 this->addPaint(paint); 452 this->addRect(rect); 453 this->validate(initialOffset, size); 454 } 455 456 void SkPictureRecord::onDrawRegion(const SkRegion& region, const SkPaint& paint) { 457 // op + paint index + region 458 size_t regionBytes = region.writeToMemory(nullptr); 459 size_t size = 2 * kUInt32Size + regionBytes; 460 size_t initialOffset = this->addDraw(DRAW_REGION, &size); 461 this->addPaint(paint); 462 fWriter.writeRegion(region); 463 this->validate(initialOffset, size); 464 } 465 466 void SkPictureRecord::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) { 467 // op + paint index + rrect 468 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory; 469 size_t initialOffset = this->addDraw(DRAW_RRECT, &size); 470 this->addPaint(paint); 471 this->addRRect(rrect); 472 this->validate(initialOffset, size); 473 } 474 475 void SkPictureRecord::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 476 const SkPaint& paint) { 477 // op + paint index + rrects 478 size_t size = 2 * kUInt32Size + SkRRect::kSizeInMemory * 2; 479 size_t initialOffset = this->addDraw(DRAW_DRRECT, &size); 480 this->addPaint(paint); 481 this->addRRect(outer); 482 this->addRRect(inner); 483 this->validate(initialOffset, size); 484 } 485 486 void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) { 487 fContentInfo.onDrawPath(path, paint); 488 489 // op + paint index + path index 490 size_t size = 3 * kUInt32Size; 491 size_t initialOffset = this->addDraw(DRAW_PATH, &size); 492 this->addPaint(paint); 493 this->addPath(path); 494 this->validate(initialOffset, size); 495 } 496 497 void SkPictureRecord::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, 498 const SkPaint* paint) { 499 // op + paint_index + image_index + x + y 500 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 501 size_t initialOffset = this->addDraw(DRAW_IMAGE, &size); 502 this->addPaintPtr(paint); 503 this->addImage(image); 504 this->addScalar(x); 505 this->addScalar(y); 506 this->validate(initialOffset, size); 507 } 508 509 void SkPictureRecord::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, 510 const SkPaint* paint, SrcRectConstraint constraint) { 511 // id + paint_index + image_index + bool_for_src + constraint 512 size_t size = 5 * kUInt32Size; 513 if (src) { 514 size += sizeof(*src); // + rect 515 } 516 size += sizeof(dst); // + rect 517 518 size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT, &size); 519 this->addPaintPtr(paint); 520 this->addImage(image); 521 this->addRectPtr(src); // may be null 522 this->addRect(dst); 523 this->addInt(constraint); 524 this->validate(initialOffset, size); 525 } 526 527 void SkPictureRecord::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst, 528 const SkPaint* paint) { 529 // id + paint_index + image_index + center + dst 530 size_t size = 3 * kUInt32Size + sizeof(SkIRect) + sizeof(SkRect); 531 532 size_t initialOffset = this->addDraw(DRAW_IMAGE_NINE, &size); 533 this->addPaintPtr(paint); 534 this->addImage(img); 535 this->addIRect(center); 536 this->addRect(dst); 537 this->validate(initialOffset, size); 538 } 539 540 void SkPictureRecord::onDrawImageLattice(const SkImage* image, const Lattice& lattice, 541 const SkRect& dst, const SkPaint* paint) { 542 // xCount + xDivs + yCount+ yDivs 543 int flagCount = (nullptr == lattice.fFlags) ? 0 : (lattice.fXCount + 1) * (lattice.fYCount + 1); 544 size_t latticeSize = (1 + lattice.fXCount + 1 + lattice.fYCount + 1) * kUInt32Size + 545 SkAlign4(flagCount * sizeof(SkCanvas::Lattice::Flags)) + sizeof(SkIRect); 546 547 // op + paint index + image index + lattice + dst rect 548 size_t size = 3 * kUInt32Size + latticeSize + sizeof(dst); 549 size_t initialOffset = this->addDraw(DRAW_IMAGE_LATTICE, &size); 550 this->addPaintPtr(paint); 551 this->addImage(image); 552 this->addInt(lattice.fXCount); 553 fWriter.writePad(lattice.fXDivs, lattice.fXCount * kUInt32Size); 554 this->addInt(lattice.fYCount); 555 fWriter.writePad(lattice.fYDivs, lattice.fYCount * kUInt32Size); 556 this->addInt(flagCount); 557 fWriter.writePad(lattice.fFlags, flagCount * sizeof(SkCanvas::Lattice::Flags)); 558 SkASSERT(lattice.fBounds); 559 this->addIRect(*lattice.fBounds); 560 this->addRect(dst); 561 this->validate(initialOffset, size); 562 } 563 564 void SkPictureRecord::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, 565 const SkPaint& paint) { 566 // op + paint index + length + 'length' worth of chars + x + y 567 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 2 * sizeof(SkScalar); 568 569 DrawType op = DRAW_TEXT; 570 size_t initialOffset = this->addDraw(op, &size); 571 this->addPaint(paint); 572 this->addText(text, byteLength); 573 this->addScalar(x); 574 this->addScalar(y); 575 this->validate(initialOffset, size); 576 } 577 578 void SkPictureRecord::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], 579 const SkPaint& paint) { 580 int points = paint.countText(text, byteLength); 581 582 // op + paint index + length + 'length' worth of data + num points + x&y point data 583 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + points * sizeof(SkPoint); 584 585 DrawType op = DRAW_POS_TEXT; 586 587 size_t initialOffset = this->addDraw(op, &size); 588 this->addPaint(paint); 589 this->addText(text, byteLength); 590 this->addInt(points); 591 fWriter.writeMul4(pos, points * sizeof(SkPoint)); 592 this->validate(initialOffset, size); 593 } 594 595 void SkPictureRecord::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], 596 SkScalar constY, const SkPaint& paint) { 597 int points = paint.countText(text, byteLength); 598 599 // op + paint index + length + 'length' worth of data + num points 600 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + 1 * kUInt32Size; 601 // + y + the actual points 602 size += 1 * kUInt32Size + points * sizeof(SkScalar); 603 604 size_t initialOffset = this->addDraw(DRAW_POS_TEXT_H, &size); 605 this->addPaint(paint); 606 this->addText(text, byteLength); 607 this->addInt(points); 608 this->addScalar(constY); 609 fWriter.writeMul4(xpos, points * sizeof(SkScalar)); 610 this->validate(initialOffset, size); 611 } 612 613 void SkPictureRecord::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, 614 const SkMatrix* matrix, const SkPaint& paint) { 615 // op + paint index + length + 'length' worth of data + path index + matrix 616 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); 617 size_t size = 3 * kUInt32Size + SkAlign4(byteLength) + kUInt32Size + m.writeToMemory(nullptr); 618 size_t initialOffset = this->addDraw(DRAW_TEXT_ON_PATH, &size); 619 this->addPaint(paint); 620 this->addText(text, byteLength); 621 this->addPath(path); 622 this->addMatrix(m); 623 this->validate(initialOffset, size); 624 } 625 626 void SkPictureRecord::onDrawTextRSXform(const void* text, size_t byteLength, 627 const SkRSXform xform[], const SkRect* cull, 628 const SkPaint& paint) { 629 const int count = paint.countText(text, byteLength); 630 // [op + paint-index + count + flags + length] + [text] + [xform] + cull 631 size_t size = 5 * kUInt32Size + SkAlign4(byteLength) + count * sizeof(SkRSXform); 632 uint32_t flags = 0; 633 if (cull) { 634 flags |= DRAW_TEXT_RSXFORM_HAS_CULL; 635 size += sizeof(SkRect); 636 } 637 638 size_t initialOffset = this->addDraw(DRAW_TEXT_RSXFORM, &size); 639 this->addPaint(paint); 640 this->addInt(count); 641 this->addInt(flags); 642 this->addText(text, byteLength); 643 fWriter.write(xform, count * sizeof(SkRSXform)); 644 if (cull) { 645 fWriter.write(cull, sizeof(SkRect)); 646 } 647 this->validate(initialOffset, size); 648 } 649 650 void SkPictureRecord::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, 651 const SkPaint& paint) { 652 653 // op + paint index + blob index + x/y 654 size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar); 655 size_t initialOffset = this->addDraw(DRAW_TEXT_BLOB, &size); 656 657 this->addPaint(paint); 658 this->addTextBlob(blob); 659 this->addScalar(x); 660 this->addScalar(y); 661 662 this->validate(initialOffset, size); 663 } 664 665 void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, 666 const SkPaint* paint) { 667 // op + picture index 668 size_t size = 2 * kUInt32Size; 669 size_t initialOffset; 670 671 if (nullptr == matrix && nullptr == paint) { 672 initialOffset = this->addDraw(DRAW_PICTURE, &size); 673 this->addPicture(picture); 674 } else { 675 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); 676 size += m.writeToMemory(nullptr) + kUInt32Size; // matrix + paint 677 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size); 678 this->addPaintPtr(paint); 679 this->addMatrix(m); 680 this->addPicture(picture); 681 } 682 this->validate(initialOffset, size); 683 } 684 685 void SkPictureRecord::onDrawShadowedPicture(const SkPicture* picture, 686 const SkMatrix* matrix, 687 const SkPaint* paint, 688 const SkShadowParams& params) { 689 // op + picture index 690 size_t size = 2 * kUInt32Size; 691 size_t initialOffset; 692 693 // TODO: handle recording params. 694 if (nullptr == matrix && nullptr == paint) { 695 initialOffset = this->addDraw(DRAW_PICTURE, &size); 696 this->addPicture(picture); 697 } else { 698 const SkMatrix& m = matrix ? *matrix : SkMatrix::I(); 699 size += m.writeToMemory(nullptr) + kUInt32Size; // matrix + paint 700 initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size); 701 this->addPaintPtr(paint); 702 this->addMatrix(m); 703 this->addPicture(picture); 704 } 705 this->validate(initialOffset, size); 706 } 707 708 void SkPictureRecord::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) { 709 // op + drawable index 710 size_t size = 2 * kUInt32Size; 711 size_t initialOffset; 712 713 if (nullptr == matrix) { 714 initialOffset = this->addDraw(DRAW_DRAWABLE, &size); 715 this->addDrawable(drawable); 716 } else { 717 size += matrix->writeToMemory(nullptr); // matrix 718 initialOffset = this->addDraw(DRAW_DRAWABLE_MATRIX, &size); 719 this->addMatrix(*matrix); 720 this->addDrawable(drawable); 721 } 722 this->validate(initialOffset, size); 723 } 724 725 void SkPictureRecord::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode mode, 726 const SkPaint& paint) { 727 // op + paint index + vertices index + mode 728 size_t size = 4 * kUInt32Size; 729 size_t initialOffset = this->addDraw(DRAW_VERTICES_OBJECT, &size); 730 731 this->addPaint(paint); 732 this->addVertices(vertices); 733 this->addInt(static_cast<uint32_t>(mode)); 734 735 this->validate(initialOffset, size); 736 } 737 738 void SkPictureRecord::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], 739 const SkPoint texCoords[4], SkBlendMode bmode, 740 const SkPaint& paint) { 741 // op + paint index + patch 12 control points + flag + patch 4 colors + 4 texture coordinates 742 size_t size = 2 * kUInt32Size + SkPatchUtils::kNumCtrlPts * sizeof(SkPoint) + kUInt32Size; 743 uint32_t flag = 0; 744 if (colors) { 745 flag |= DRAW_VERTICES_HAS_COLORS; 746 size += SkPatchUtils::kNumCorners * sizeof(SkColor); 747 } 748 if (texCoords) { 749 flag |= DRAW_VERTICES_HAS_TEXS; 750 size += SkPatchUtils::kNumCorners * sizeof(SkPoint); 751 } 752 if (SkBlendMode::kModulate != bmode) { 753 flag |= DRAW_VERTICES_HAS_XFER; 754 size += kUInt32Size; 755 } 756 757 size_t initialOffset = this->addDraw(DRAW_PATCH, &size); 758 this->addPaint(paint); 759 this->addPatch(cubics); 760 this->addInt(flag); 761 762 // write optional parameters 763 if (colors) { 764 fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor)); 765 } 766 if (texCoords) { 767 fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint)); 768 } 769 if (flag & DRAW_VERTICES_HAS_XFER) { 770 this->addInt((int)bmode); 771 } 772 this->validate(initialOffset, size); 773 } 774 775 void SkPictureRecord::onDrawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRect tex[], 776 const SkColor colors[], int count, SkBlendMode mode, 777 const SkRect* cull, const SkPaint* paint) { 778 // [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull 779 size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect); 780 uint32_t flags = 0; 781 if (colors) { 782 flags |= DRAW_ATLAS_HAS_COLORS; 783 size += count * sizeof(SkColor); 784 size += sizeof(uint32_t); // xfermode::mode 785 } 786 if (cull) { 787 flags |= DRAW_ATLAS_HAS_CULL; 788 size += sizeof(SkRect); 789 } 790 791 size_t initialOffset = this->addDraw(DRAW_ATLAS, &size); 792 this->addPaintPtr(paint); 793 this->addImage(atlas); 794 this->addInt(flags); 795 this->addInt(count); 796 fWriter.write(xform, count * sizeof(SkRSXform)); 797 fWriter.write(tex, count * sizeof(SkRect)); 798 799 // write optional parameters 800 if (colors) { 801 fWriter.write(colors, count * sizeof(SkColor)); 802 this->addInt((int)mode); 803 } 804 if (cull) { 805 fWriter.write(cull, sizeof(SkRect)); 806 } 807 this->validate(initialOffset, size); 808 } 809 810 void SkPictureRecord::onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) { 811 size_t keyLen = fWriter.WriteStringSize(key); 812 size_t valueLen = fWriter.WriteDataSize(value); 813 size_t size = 4 + sizeof(SkRect) + keyLen + valueLen; 814 815 size_t initialOffset = this->addDraw(DRAW_ANNOTATION, &size); 816 this->addRect(rect); 817 fWriter.writeString(key); 818 fWriter.writeData(value); 819 this->validate(initialOffset, size); 820 } 821 822 /////////////////////////////////////////////////////////////////////////////// 823 824 template <typename T> int find_or_append_uniqueID(SkTDArray<const T*>& array, const T* obj) { 825 int index = array.select([&](const T* elem) { 826 return elem->uniqueID() == obj->uniqueID(); 827 }); 828 if (index < 0) { 829 index = array.count(); 830 *array.append() = SkRef(obj); 831 } 832 return index; 833 } 834 835 sk_sp<SkSurface> SkPictureRecord::onNewSurface(const SkImageInfo& info, const SkSurfaceProps&) { 836 return nullptr; 837 } 838 839 void SkPictureRecord::addImage(const SkImage* image) { 840 // convention for images is 0-based index 841 this->addInt(find_or_append_uniqueID(fImageRefs, image)); 842 } 843 844 void SkPictureRecord::addMatrix(const SkMatrix& matrix) { 845 fWriter.writeMatrix(matrix); 846 } 847 848 void SkPictureRecord::addPaintPtr(const SkPaint* paint) { 849 fContentInfo.onAddPaintPtr(paint); 850 851 if (paint) { 852 fPaints.push_back(*paint); 853 this->addInt(fPaints.count()); 854 } else { 855 this->addInt(0); 856 } 857 } 858 859 int SkPictureRecord::addPathToHeap(const SkPath& path) { 860 if (int* n = fPaths.find(path)) { 861 return *n; 862 } 863 int n = fPaths.count() + 1; // 0 is reserved for null / error. 864 fPaths.set(path, n); 865 return n; 866 } 867 868 void SkPictureRecord::addPath(const SkPath& path) { 869 this->addInt(this->addPathToHeap(path)); 870 } 871 872 void SkPictureRecord::addPatch(const SkPoint cubics[12]) { 873 fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint)); 874 } 875 876 void SkPictureRecord::addPicture(const SkPicture* picture) { 877 // follow the convention of recording a 1-based index 878 this->addInt(find_or_append_uniqueID(fPictureRefs, picture) + 1); 879 } 880 881 void SkPictureRecord::addDrawable(SkDrawable* drawable) { 882 int index = fDrawableRefs.find(drawable); 883 if (index < 0) { // not found 884 index = fDrawableRefs.count(); 885 *fDrawableRefs.append() = drawable; 886 drawable->ref(); 887 } 888 // follow the convention of recording a 1-based index 889 this->addInt(index + 1); 890 } 891 892 void SkPictureRecord::addPoint(const SkPoint& point) { 893 fWriter.writePoint(point); 894 } 895 896 void SkPictureRecord::addPoints(const SkPoint pts[], int count) { 897 fWriter.writeMul4(pts, count * sizeof(SkPoint)); 898 } 899 900 void SkPictureRecord::addNoOp() { 901 size_t size = kUInt32Size; // op 902 this->addDraw(NOOP, &size); 903 } 904 905 void SkPictureRecord::addRect(const SkRect& rect) { 906 fWriter.writeRect(rect); 907 } 908 909 void SkPictureRecord::addRectPtr(const SkRect* rect) { 910 if (fWriter.writeBool(rect != nullptr)) { 911 fWriter.writeRect(*rect); 912 } 913 } 914 915 void SkPictureRecord::addIRect(const SkIRect& rect) { 916 fWriter.write(&rect, sizeof(rect)); 917 } 918 919 void SkPictureRecord::addIRectPtr(const SkIRect* rect) { 920 if (fWriter.writeBool(rect != nullptr)) { 921 *(SkIRect*)fWriter.reserve(sizeof(SkIRect)) = *rect; 922 } 923 } 924 925 void SkPictureRecord::addRRect(const SkRRect& rrect) { 926 fWriter.writeRRect(rrect); 927 } 928 929 void SkPictureRecord::addRegion(const SkRegion& region) { 930 fWriter.writeRegion(region); 931 } 932 933 void SkPictureRecord::addText(const void* text, size_t byteLength) { 934 fContentInfo.onDrawText(); 935 addInt(SkToInt(byteLength)); 936 fWriter.writePad(text, byteLength); 937 } 938 939 void SkPictureRecord::addTextBlob(const SkTextBlob* blob) { 940 // follow the convention of recording a 1-based index 941 this->addInt(find_or_append_uniqueID(fTextBlobRefs, blob) + 1); 942 } 943 944 void SkPictureRecord::addVertices(const SkVertices* vertices) { 945 // follow the convention of recording a 1-based index 946 this->addInt(find_or_append_uniqueID(fVerticesRefs, vertices) + 1); 947 } 948 949 /////////////////////////////////////////////////////////////////////////////// 950