1 /* 2 * Copyright 2012 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 "SkBigPicture.h" 9 #include "SkBBoxHierarchy.h" 10 #include "SkBlurImageFilter.h" 11 #include "SkCanvas.h" 12 #include "SkColorMatrixFilter.h" 13 #include "SkColorPriv.h" 14 #include "SkDashPathEffect.h" 15 #include "SkData.h" 16 #include "SkImageGenerator.h" 17 #include "SkImageEncoder.h" 18 #include "SkImageGenerator.h" 19 #include "SkMD5.h" 20 #include "SkMiniRecorder.h" 21 #include "SkPaint.h" 22 #include "SkPicture.h" 23 #include "SkPictureRecorder.h" 24 #include "SkPixelRef.h" 25 #include "SkRectPriv.h" 26 #include "SkRRect.h" 27 #include "SkRandom.h" 28 #include "SkRecord.h" 29 #include "SkShader.h" 30 #include "SkStream.h" 31 #include "sk_tool_utils.h" 32 33 #include "Test.h" 34 35 #include "SkLumaColorFilter.h" 36 #include "SkColorFilterImageFilter.h" 37 38 static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) { 39 bm->allocN32Pixels(w, h); 40 bm->eraseColor(color); 41 if (immutable) { 42 bm->setImmutable(); 43 } 44 } 45 46 #ifdef SK_DEBUG 47 // Ensure that deleting an empty SkPicture does not assert. Asserts only fire 48 // in debug mode, so only run in debug mode. 49 static void test_deleting_empty_picture() { 50 SkPictureRecorder recorder; 51 // Creates an SkPictureRecord 52 recorder.beginRecording(0, 0); 53 // Turns that into an SkPicture 54 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 55 // Ceates a new SkPictureRecord 56 recorder.beginRecording(0, 0); 57 } 58 59 // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode. 60 static void test_serializing_empty_picture() { 61 SkPictureRecorder recorder; 62 recorder.beginRecording(0, 0); 63 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 64 SkDynamicMemoryWStream stream; 65 picture->serialize(&stream); 66 } 67 #endif 68 69 static void rand_op(SkCanvas* canvas, SkRandom& rand) { 70 SkPaint paint; 71 SkRect rect = SkRect::MakeWH(50, 50); 72 73 SkScalar unit = rand.nextUScalar1(); 74 if (unit <= 0.3) { 75 // SkDebugf("save\n"); 76 canvas->save(); 77 } else if (unit <= 0.6) { 78 // SkDebugf("restore\n"); 79 canvas->restore(); 80 } else if (unit <= 0.9) { 81 // SkDebugf("clip\n"); 82 canvas->clipRect(rect); 83 } else { 84 // SkDebugf("draw\n"); 85 canvas->drawPaint(paint); 86 } 87 } 88 89 static void set_canvas_to_save_count_4(SkCanvas* canvas) { 90 canvas->restoreToCount(1); 91 canvas->save(); 92 canvas->save(); 93 canvas->save(); 94 } 95 96 /** 97 * A canvas that records the number of saves, saveLayers and restores. 98 */ 99 class SaveCountingCanvas : public SkCanvas { 100 public: 101 SaveCountingCanvas(int width, int height) 102 : INHERITED(width, height) 103 , fSaveCount(0) 104 , fSaveLayerCount(0) 105 , fRestoreCount(0){ 106 } 107 108 SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override { 109 ++fSaveLayerCount; 110 return this->INHERITED::getSaveLayerStrategy(rec); 111 } 112 113 void willSave() override { 114 ++fSaveCount; 115 this->INHERITED::willSave(); 116 } 117 118 void willRestore() override { 119 ++fRestoreCount; 120 this->INHERITED::willRestore(); 121 } 122 123 unsigned int getSaveCount() const { return fSaveCount; } 124 unsigned int getSaveLayerCount() const { return fSaveLayerCount; } 125 unsigned int getRestoreCount() const { return fRestoreCount; } 126 127 private: 128 unsigned int fSaveCount; 129 unsigned int fSaveLayerCount; 130 unsigned int fRestoreCount; 131 132 typedef SkCanvas INHERITED; 133 }; 134 135 void check_save_state(skiatest::Reporter* reporter, SkPicture* picture, 136 unsigned int numSaves, unsigned int numSaveLayers, 137 unsigned int numRestores) { 138 SaveCountingCanvas canvas(SkScalarCeilToInt(picture->cullRect().width()), 139 SkScalarCeilToInt(picture->cullRect().height())); 140 141 picture->playback(&canvas); 142 143 // Optimizations may have removed these, 144 // so expect to have seen no more than num{Saves,SaveLayers,Restores}. 145 REPORTER_ASSERT(reporter, numSaves >= canvas.getSaveCount()); 146 REPORTER_ASSERT(reporter, numSaveLayers >= canvas.getSaveLayerCount()); 147 REPORTER_ASSERT(reporter, numRestores >= canvas.getRestoreCount()); 148 } 149 150 // This class exists so SkPicture can friend it and give it access to 151 // the 'partialReplay' method. 152 class SkPictureRecorderReplayTester { 153 public: 154 static sk_sp<SkPicture> Copy(SkPictureRecorder* recorder) { 155 SkPictureRecorder recorder2; 156 157 SkCanvas* canvas = recorder2.beginRecording(10, 10); 158 159 recorder->partialReplay(canvas); 160 161 return recorder2.finishRecordingAsPicture(); 162 } 163 }; 164 165 static void create_imbalance(SkCanvas* canvas) { 166 SkRect clipRect = SkRect::MakeWH(2, 2); 167 SkRect drawRect = SkRect::MakeWH(10, 10); 168 canvas->save(); 169 canvas->clipRect(clipRect, kReplace_SkClipOp); 170 canvas->translate(1.0f, 1.0f); 171 SkPaint p; 172 p.setColor(SK_ColorGREEN); 173 canvas->drawRect(drawRect, p); 174 // no restore 175 } 176 177 // This tests that replaying a potentially unbalanced picture into a canvas 178 // doesn't affect the canvas' save count or matrix/clip state. 179 static void check_balance(skiatest::Reporter* reporter, SkPicture* picture) { 180 SkBitmap bm; 181 bm.allocN32Pixels(4, 3); 182 SkCanvas canvas(bm); 183 184 int beforeSaveCount = canvas.getSaveCount(); 185 186 SkMatrix beforeMatrix = canvas.getTotalMatrix(); 187 188 SkRect beforeClip = canvas.getLocalClipBounds(); 189 190 canvas.drawPicture(picture); 191 192 REPORTER_ASSERT(reporter, beforeSaveCount == canvas.getSaveCount()); 193 REPORTER_ASSERT(reporter, beforeMatrix == canvas.getTotalMatrix()); 194 195 SkRect afterClip = canvas.getLocalClipBounds(); 196 197 REPORTER_ASSERT(reporter, afterClip == beforeClip); 198 } 199 200 // Test out SkPictureRecorder::partialReplay 201 DEF_TEST(PictureRecorder_replay, reporter) { 202 // check save/saveLayer state 203 { 204 SkPictureRecorder recorder; 205 206 SkCanvas* canvas = recorder.beginRecording(10, 10); 207 208 canvas->saveLayer(nullptr, nullptr); 209 210 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder)); 211 212 // The extra save and restore comes from the Copy process. 213 check_save_state(reporter, copy.get(), 2, 1, 3); 214 215 canvas->saveLayer(nullptr, nullptr); 216 217 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture()); 218 219 check_save_state(reporter, final.get(), 1, 2, 3); 220 221 // The copy shouldn't pick up any operations added after it was made 222 check_save_state(reporter, copy.get(), 2, 1, 3); 223 } 224 225 // Recreate the Android partialReplay test case 226 { 227 SkPictureRecorder recorder; 228 229 SkCanvas* canvas = recorder.beginRecording(4, 3, nullptr, 0); 230 create_imbalance(canvas); 231 232 int expectedSaveCount = canvas->getSaveCount(); 233 234 sk_sp<SkPicture> copy(SkPictureRecorderReplayTester::Copy(&recorder)); 235 check_balance(reporter, copy.get()); 236 237 REPORTER_ASSERT(reporter, expectedSaveCount = canvas->getSaveCount()); 238 239 // End the recording of source to test the picture finalization 240 // process isn't complicated by the partialReplay step 241 sk_sp<SkPicture> final(recorder.finishRecordingAsPicture()); 242 } 243 } 244 245 static void test_unbalanced_save_restores(skiatest::Reporter* reporter) { 246 SkCanvas testCanvas(100, 100); 247 set_canvas_to_save_count_4(&testCanvas); 248 249 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); 250 251 SkPaint paint; 252 SkRect rect = SkRect::MakeLTRB(-10000000, -10000000, 10000000, 10000000); 253 254 SkPictureRecorder recorder; 255 256 { 257 // Create picture with 2 unbalanced saves 258 SkCanvas* canvas = recorder.beginRecording(100, 100); 259 canvas->save(); 260 canvas->translate(10, 10); 261 canvas->drawRect(rect, paint); 262 canvas->save(); 263 canvas->translate(10, 10); 264 canvas->drawRect(rect, paint); 265 sk_sp<SkPicture> extraSavePicture(recorder.finishRecordingAsPicture()); 266 267 testCanvas.drawPicture(extraSavePicture); 268 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); 269 } 270 271 set_canvas_to_save_count_4(&testCanvas); 272 273 { 274 // Create picture with 2 unbalanced restores 275 SkCanvas* canvas = recorder.beginRecording(100, 100); 276 canvas->save(); 277 canvas->translate(10, 10); 278 canvas->drawRect(rect, paint); 279 canvas->save(); 280 canvas->translate(10, 10); 281 canvas->drawRect(rect, paint); 282 canvas->restore(); 283 canvas->restore(); 284 canvas->restore(); 285 canvas->restore(); 286 sk_sp<SkPicture> extraRestorePicture(recorder.finishRecordingAsPicture()); 287 288 testCanvas.drawPicture(extraRestorePicture); 289 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); 290 } 291 292 set_canvas_to_save_count_4(&testCanvas); 293 294 { 295 SkCanvas* canvas = recorder.beginRecording(100, 100); 296 canvas->translate(10, 10); 297 canvas->drawRect(rect, paint); 298 sk_sp<SkPicture> noSavePicture(recorder.finishRecordingAsPicture()); 299 300 testCanvas.drawPicture(noSavePicture); 301 REPORTER_ASSERT(reporter, 4 == testCanvas.getSaveCount()); 302 REPORTER_ASSERT(reporter, testCanvas.getTotalMatrix().isIdentity()); 303 } 304 } 305 306 static void test_peephole() { 307 SkRandom rand; 308 309 SkPictureRecorder recorder; 310 311 for (int j = 0; j < 100; j++) { 312 SkRandom rand2(rand); // remember the seed 313 314 SkCanvas* canvas = recorder.beginRecording(100, 100); 315 316 for (int i = 0; i < 1000; ++i) { 317 rand_op(canvas, rand); 318 } 319 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 320 321 rand = rand2; 322 } 323 324 { 325 SkCanvas* canvas = recorder.beginRecording(100, 100); 326 SkRect rect = SkRect::MakeWH(50, 50); 327 328 for (int i = 0; i < 100; ++i) { 329 canvas->save(); 330 } 331 while (canvas->getSaveCount() > 1) { 332 canvas->clipRect(rect); 333 canvas->restore(); 334 } 335 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 336 } 337 } 338 339 #ifndef SK_DEBUG 340 // Only test this is in release mode. We deliberately crash in debug mode, since a valid caller 341 // should never do this. 342 static void test_bad_bitmap() { 343 // This bitmap has a width and height but no pixels. As a result, attempting to record it will 344 // fail. 345 SkBitmap bm; 346 bm.setInfo(SkImageInfo::MakeN32Premul(100, 100)); 347 SkPictureRecorder recorder; 348 SkCanvas* recordingCanvas = recorder.beginRecording(100, 100); 349 recordingCanvas->drawBitmap(bm, 0, 0); 350 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 351 352 SkCanvas canvas; 353 canvas.drawPicture(picture); 354 } 355 #endif 356 357 static void test_clip_bound_opt(skiatest::Reporter* reporter) { 358 // Test for crbug.com/229011 359 SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4), 360 SkIntToScalar(2), SkIntToScalar(2)); 361 SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7), 362 SkIntToScalar(1), SkIntToScalar(1)); 363 SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6), 364 SkIntToScalar(1), SkIntToScalar(1)); 365 366 SkPath invPath; 367 invPath.addOval(rect1); 368 invPath.setFillType(SkPath::kInverseEvenOdd_FillType); 369 SkPath path; 370 path.addOval(rect2); 371 SkPath path2; 372 path2.addOval(rect3); 373 SkIRect clipBounds; 374 SkPictureRecorder recorder; 375 376 // Testing conservative-raster-clip that is enabled by PictureRecord 377 { 378 SkCanvas* canvas = recorder.beginRecording(10, 10); 379 canvas->clipPath(invPath); 380 clipBounds = canvas->getDeviceClipBounds(); 381 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft); 382 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop); 383 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom); 384 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight); 385 } 386 { 387 SkCanvas* canvas = recorder.beginRecording(10, 10); 388 canvas->clipPath(path); 389 canvas->clipPath(invPath); 390 clipBounds = canvas->getDeviceClipBounds(); 391 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft); 392 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop); 393 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom); 394 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight); 395 } 396 { 397 SkCanvas* canvas = recorder.beginRecording(10, 10); 398 canvas->clipPath(path); 399 canvas->clipPath(invPath, kUnion_SkClipOp); 400 clipBounds = canvas->getDeviceClipBounds(); 401 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft); 402 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop); 403 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom); 404 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight); 405 } 406 { 407 SkCanvas* canvas = recorder.beginRecording(10, 10); 408 canvas->clipPath(path, kDifference_SkClipOp); 409 clipBounds = canvas->getDeviceClipBounds(); 410 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft); 411 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop); 412 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom); 413 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight); 414 } 415 { 416 SkCanvas* canvas = recorder.beginRecording(10, 10); 417 canvas->clipPath(path, kReverseDifference_SkClipOp); 418 clipBounds = canvas->getDeviceClipBounds(); 419 // True clip is actually empty in this case, but the best 420 // determination we can make using only bounds as input is that the 421 // clip is included in the bounds of 'path'. 422 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft); 423 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop); 424 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom); 425 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight); 426 } 427 { 428 SkCanvas* canvas = recorder.beginRecording(10, 10); 429 canvas->clipPath(path, kIntersect_SkClipOp); 430 canvas->clipPath(path2, kXOR_SkClipOp); 431 clipBounds = canvas->getDeviceClipBounds(); 432 REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft); 433 REPORTER_ASSERT(reporter, 6 == clipBounds.fTop); 434 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom); 435 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight); 436 } 437 } 438 439 static void test_cull_rect_reset(skiatest::Reporter* reporter) { 440 SkPictureRecorder recorder; 441 SkRect bounds = SkRect::MakeWH(10, 10); 442 SkRTreeFactory factory; 443 SkCanvas* canvas = recorder.beginRecording(bounds, &factory); 444 bounds = SkRect::MakeWH(100, 100); 445 SkPaint paint; 446 canvas->drawRect(bounds, paint); 447 canvas->drawRect(bounds, paint); 448 sk_sp<SkPicture> p(recorder.finishRecordingAsPictureWithCull(bounds)); 449 const SkBigPicture* picture = p->asSkBigPicture(); 450 REPORTER_ASSERT(reporter, picture); 451 452 SkRect finalCullRect = picture->cullRect(); 453 REPORTER_ASSERT(reporter, 0 == finalCullRect.fLeft); 454 REPORTER_ASSERT(reporter, 0 == finalCullRect.fTop); 455 REPORTER_ASSERT(reporter, 100 == finalCullRect.fBottom); 456 REPORTER_ASSERT(reporter, 100 == finalCullRect.fRight); 457 458 const SkBBoxHierarchy* pictureBBH = picture->bbh(); 459 SkRect bbhCullRect = pictureBBH->getRootBound(); 460 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fLeft); 461 REPORTER_ASSERT(reporter, 0 == bbhCullRect.fTop); 462 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fBottom); 463 REPORTER_ASSERT(reporter, 100 == bbhCullRect.fRight); 464 } 465 466 467 /** 468 * A canvas that records the number of clip commands. 469 */ 470 class ClipCountingCanvas : public SkCanvas { 471 public: 472 ClipCountingCanvas(int width, int height) 473 : INHERITED(width, height) 474 , fClipCount(0){ 475 } 476 477 void onClipRect(const SkRect& r, SkClipOp op, ClipEdgeStyle edgeStyle) override { 478 fClipCount += 1; 479 this->INHERITED::onClipRect(r, op, edgeStyle); 480 } 481 482 void onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle edgeStyle)override { 483 fClipCount += 1; 484 this->INHERITED::onClipRRect(rrect, op, edgeStyle); 485 } 486 487 void onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle edgeStyle) override { 488 fClipCount += 1; 489 this->INHERITED::onClipPath(path, op, edgeStyle); 490 } 491 492 void onClipRegion(const SkRegion& deviceRgn, SkClipOp op) override { 493 fClipCount += 1; 494 this->INHERITED::onClipRegion(deviceRgn, op); 495 } 496 497 unsigned getClipCount() const { return fClipCount; } 498 499 private: 500 unsigned fClipCount; 501 502 typedef SkCanvas INHERITED; 503 }; 504 505 static void test_clip_expansion(skiatest::Reporter* reporter) { 506 SkPictureRecorder recorder; 507 SkCanvas* canvas = recorder.beginRecording(10, 10); 508 509 canvas->clipRect(SkRect::MakeEmpty(), kReplace_SkClipOp); 510 // The following expanding clip should not be skipped. 511 canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), kUnion_SkClipOp); 512 // Draw something so the optimizer doesn't just fold the world. 513 SkPaint p; 514 p.setColor(SK_ColorBLUE); 515 canvas->drawPaint(p); 516 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 517 518 ClipCountingCanvas testCanvas(10, 10); 519 picture->playback(&testCanvas); 520 521 // Both clips should be present on playback. 522 REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2); 523 } 524 525 static void test_gen_id(skiatest::Reporter* reporter) { 526 527 SkPictureRecorder recorder; 528 recorder.beginRecording(0, 0); 529 sk_sp<SkPicture> empty(recorder.finishRecordingAsPicture()); 530 531 // Empty pictures should still have a valid ID 532 REPORTER_ASSERT(reporter, empty->uniqueID() != SK_InvalidGenID); 533 534 SkCanvas* canvas = recorder.beginRecording(1, 1); 535 canvas->drawColor(SK_ColorWHITE); 536 sk_sp<SkPicture> hasData(recorder.finishRecordingAsPicture()); 537 // picture should have a non-zero id after recording 538 REPORTER_ASSERT(reporter, hasData->uniqueID() != SK_InvalidGenID); 539 540 // both pictures should have different ids 541 REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID()); 542 } 543 544 static void test_typeface(skiatest::Reporter* reporter) { 545 SkPictureRecorder recorder; 546 SkCanvas* canvas = recorder.beginRecording(10, 10); 547 SkPaint paint; 548 paint.setTypeface(SkTypeface::MakeFromName("Arial", SkFontStyle::Italic())); 549 canvas->drawString("Q", 0, 10, paint); 550 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 551 SkDynamicMemoryWStream stream; 552 picture->serialize(&stream); 553 } 554 555 DEF_TEST(Picture, reporter) { 556 test_typeface(reporter); 557 #ifdef SK_DEBUG 558 test_deleting_empty_picture(); 559 test_serializing_empty_picture(); 560 #else 561 test_bad_bitmap(); 562 #endif 563 test_unbalanced_save_restores(reporter); 564 test_peephole(); 565 test_clip_bound_opt(reporter); 566 test_clip_expansion(reporter); 567 test_gen_id(reporter); 568 test_cull_rect_reset(reporter); 569 } 570 571 static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) { 572 const SkPaint paint; 573 const SkRect rect = { 5.0f, 5.0f, 8.0f, 8.0f }; 574 const SkIRect irect = { 2, 2, 3, 3 }; 575 int divs[] = { 2, 3 }; 576 SkCanvas::Lattice lattice; 577 lattice.fXCount = lattice.fYCount = 2; 578 lattice.fXDivs = lattice.fYDivs = divs; 579 580 // Don't care what these record, as long as they're legal. 581 canvas->drawBitmap(bitmap, 0.0f, 0.0f, &paint); 582 canvas->drawBitmapRect(bitmap, rect, rect, &paint, SkCanvas::kStrict_SrcRectConstraint); 583 canvas->drawBitmapNine(bitmap, irect, rect, &paint); 584 canvas->drawBitmap(bitmap, 1, 1); // drawSprite 585 canvas->drawBitmapLattice(bitmap, lattice, rect, &paint); 586 } 587 588 static void test_draw_bitmaps(SkCanvas* canvas) { 589 SkBitmap empty; 590 draw_bitmaps(empty, canvas); 591 empty.setInfo(SkImageInfo::MakeN32Premul(10, 10)); 592 draw_bitmaps(empty, canvas); 593 } 594 595 DEF_TEST(Picture_EmptyBitmap, r) { 596 SkPictureRecorder recorder; 597 test_draw_bitmaps(recorder.beginRecording(10, 10)); 598 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 599 } 600 601 DEF_TEST(Canvas_EmptyBitmap, r) { 602 SkBitmap dst; 603 dst.allocN32Pixels(10, 10); 604 SkCanvas canvas(dst); 605 606 test_draw_bitmaps(&canvas); 607 } 608 609 DEF_TEST(DontOptimizeSaveLayerDrawDrawRestore, reporter) { 610 // This test is from crbug.com/344987. 611 // The commands are: 612 // saveLayer with paint that modifies alpha 613 // drawBitmapRect 614 // drawBitmapRect 615 // restore 616 // The bug was that this structure was modified so that: 617 // - The saveLayer and restore were eliminated 618 // - The alpha was only applied to the first drawBitmapRectToRect 619 620 // This test draws blue and red squares inside a 50% transparent 621 // layer. Both colours should show up muted. 622 // When the bug is present, the red square (the second bitmap) 623 // shows upwith full opacity. 624 625 SkBitmap blueBM; 626 make_bm(&blueBM, 100, 100, SkColorSetARGB(255, 0, 0, 255), true); 627 SkBitmap redBM; 628 make_bm(&redBM, 100, 100, SkColorSetARGB(255, 255, 0, 0), true); 629 SkPaint semiTransparent; 630 semiTransparent.setAlpha(0x80); 631 632 SkPictureRecorder recorder; 633 SkCanvas* canvas = recorder.beginRecording(100, 100); 634 canvas->drawColor(0); 635 636 canvas->saveLayer(nullptr, &semiTransparent); 637 canvas->drawBitmap(blueBM, 25, 25); 638 canvas->drawBitmap(redBM, 50, 50); 639 canvas->restore(); 640 641 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 642 643 // Now replay the picture back on another canvas 644 // and check a couple of its pixels. 645 SkBitmap replayBM; 646 make_bm(&replayBM, 100, 100, SK_ColorBLACK, false); 647 SkCanvas replayCanvas(replayBM); 648 picture->playback(&replayCanvas); 649 replayCanvas.flush(); 650 651 // With the bug present, at (55, 55) we would get a fully opaque red 652 // intead of a dark red. 653 REPORTER_ASSERT(reporter, replayBM.getColor(30, 30) == 0xff000080); 654 REPORTER_ASSERT(reporter, replayBM.getColor(55, 55) == 0xff800000); 655 } 656 657 struct CountingBBH : public SkBBoxHierarchy { 658 mutable int searchCalls; 659 SkRect rootBound; 660 661 CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {} 662 663 void search(const SkRect& query, SkTDArray<int>* results) const override { 664 this->searchCalls++; 665 } 666 667 void insert(const SkRect[], int) override {} 668 virtual size_t bytesUsed() const override { return 0; } 669 SkRect getRootBound() const override { return rootBound; } 670 }; 671 672 class SpoonFedBBHFactory : public SkBBHFactory { 673 public: 674 explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {} 675 SkBBoxHierarchy* operator()(const SkRect&) const override { 676 return SkRef(fBBH); 677 } 678 private: 679 SkBBoxHierarchy* fBBH; 680 }; 681 682 // When the canvas clip covers the full picture, we don't need to call the BBH. 683 DEF_TEST(Picture_SkipBBH, r) { 684 SkRect bound = SkRect::MakeWH(320, 240); 685 CountingBBH bbh(bound); 686 SpoonFedBBHFactory factory(&bbh); 687 688 SkPictureRecorder recorder; 689 SkCanvas* c = recorder.beginRecording(bound, &factory); 690 // Record a few ops so we don't hit a small- or empty- picture optimization. 691 c->drawRect(bound, SkPaint()); 692 c->drawRect(bound, SkPaint()); 693 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 694 695 SkCanvas big(640, 480), small(300, 200); 696 697 picture->playback(&big); 698 REPORTER_ASSERT(r, bbh.searchCalls == 0); 699 700 picture->playback(&small); 701 REPORTER_ASSERT(r, bbh.searchCalls == 1); 702 } 703 704 DEF_TEST(Picture_BitmapLeak, r) { 705 SkBitmap mut, immut; 706 mut.allocN32Pixels(300, 200); 707 immut.allocN32Pixels(300, 200); 708 immut.setImmutable(); 709 SkASSERT(!mut.isImmutable()); 710 SkASSERT(immut.isImmutable()); 711 712 // No one can hold a ref on our pixels yet. 713 REPORTER_ASSERT(r, mut.pixelRef()->unique()); 714 REPORTER_ASSERT(r, immut.pixelRef()->unique()); 715 716 sk_sp<SkPicture> pic; 717 { 718 // we want the recorder to go out of scope before our subsequent checks, so we 719 // place it inside local braces. 720 SkPictureRecorder rec; 721 SkCanvas* canvas = rec.beginRecording(1920, 1200); 722 canvas->drawBitmap(mut, 0, 0); 723 canvas->drawBitmap(immut, 800, 600); 724 pic = rec.finishRecordingAsPicture(); 725 } 726 727 // The picture shares the immutable pixels but copies the mutable ones. 728 REPORTER_ASSERT(r, mut.pixelRef()->unique()); 729 REPORTER_ASSERT(r, !immut.pixelRef()->unique()); 730 731 // When the picture goes away, it's just our bitmaps holding the refs. 732 pic = nullptr; 733 REPORTER_ASSERT(r, mut.pixelRef()->unique()); 734 REPORTER_ASSERT(r, immut.pixelRef()->unique()); 735 } 736 737 // getRecordingCanvas() should return a SkCanvas when recording, null when not recording. 738 DEF_TEST(Picture_getRecordingCanvas, r) { 739 SkPictureRecorder rec; 740 REPORTER_ASSERT(r, !rec.getRecordingCanvas()); 741 for (int i = 0; i < 3; i++) { 742 rec.beginRecording(100, 100); 743 REPORTER_ASSERT(r, rec.getRecordingCanvas()); 744 rec.finishRecordingAsPicture(); 745 REPORTER_ASSERT(r, !rec.getRecordingCanvas()); 746 } 747 } 748 749 DEF_TEST(MiniRecorderLeftHanging, r) { 750 // Any shader or other ref-counted effect will do just fine here. 751 SkPaint paint; 752 paint.setShader(SkShader::MakeColorShader(SK_ColorRED)); 753 754 SkMiniRecorder rec; 755 REPORTER_ASSERT(r, rec.drawRect(SkRect::MakeWH(20,30), paint)); 756 // Don't call rec.detachPicture(). Test succeeds by not asserting or leaking the shader. 757 } 758 759 DEF_TEST(Picture_preserveCullRect, r) { 760 SkPictureRecorder recorder; 761 762 SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4)); 763 c->clear(SK_ColorCYAN); 764 765 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); 766 SkDynamicMemoryWStream wstream; 767 picture->serialize(&wstream); 768 769 std::unique_ptr<SkStream> rstream(wstream.detachAsStream()); 770 sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream.get())); 771 772 REPORTER_ASSERT(r, deserializedPicture != nullptr); 773 REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1); 774 REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2); 775 REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3); 776 REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4); 777 } 778 779 780 // If we record bounded ops into a picture with a big cull and calculate the 781 // bounds of those ops, we should trim down the picture cull to the ops' bounds. 782 // If we're not using an SkBBH, we shouldn't change it. 783 DEF_TEST(Picture_UpdatedCull_1, r) { 784 // Testing 1 draw exercises SkMiniPicture. 785 SkRTreeFactory factory; 786 SkPictureRecorder recorder; 787 788 auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory); 789 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{}); 790 auto pic = recorder.finishRecordingAsPicture(); 791 REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,20)); 792 793 canvas = recorder.beginRecording(SkRectPriv::MakeLargest()); 794 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{}); 795 pic = recorder.finishRecordingAsPicture(); 796 REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest()); 797 } 798 DEF_TEST(Picture_UpdatedCull_2, r) { 799 // Testing >1 draw exercises SkBigPicture. 800 SkRTreeFactory factory; 801 SkPictureRecorder recorder; 802 803 auto canvas = recorder.beginRecording(SkRectPriv::MakeLargest(), &factory); 804 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{}); 805 canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{}); 806 auto pic = recorder.finishRecordingAsPicture(); 807 REPORTER_ASSERT(r, pic->cullRect() == SkRect::MakeWH(20,40)); 808 809 canvas = recorder.beginRecording(SkRectPriv::MakeLargest()); 810 canvas->drawRect(SkRect::MakeWH(20,20), SkPaint{}); 811 canvas->drawRect(SkRect::MakeWH(10,40), SkPaint{}); 812 pic = recorder.finishRecordingAsPicture(); 813 REPORTER_ASSERT(r, pic->cullRect() == SkRectPriv::MakeLargest()); 814 } 815 816 DEF_TEST(Picture_RecordsFlush, r) { 817 SkPictureRecorder recorder; 818 819 auto canvas = recorder.beginRecording(SkRect::MakeWH(100,100)); 820 for (int i = 0; i < 10; i++) { 821 canvas->clear(0); 822 for (int j = 0; j < 10; j++) { 823 canvas->drawRect(SkRect::MakeXYWH(i*10,j*10,10,10), SkPaint()); 824 } 825 canvas->flush(); 826 } 827 828 // Did we record the flushes? 829 auto pic = recorder.finishRecordingAsPicture(); 830 REPORTER_ASSERT(r, pic->approximateOpCount() == 120); // 10 clears, 100 draws, 10 flushes 831 832 // Do we serialize and deserialize flushes? 833 auto skp = pic->serialize(); 834 auto back = SkPicture::MakeFromData(skp->data(), skp->size()); 835 REPORTER_ASSERT(r, back->approximateOpCount() == pic->approximateOpCount()); 836 } 837 838 DEF_TEST(Placeholder, r) { 839 SkRect cull = { 0,0, 10,20 }; 840 841 // Each placeholder is unique. 842 sk_sp<SkPicture> p1 = SkPicture::MakePlaceholder(cull), 843 p2 = SkPicture::MakePlaceholder(cull); 844 REPORTER_ASSERT(r, p1->cullRect() == p2->cullRect()); 845 REPORTER_ASSERT(r, p1->cullRect() == cull); 846 REPORTER_ASSERT(r, p1->uniqueID() != p2->uniqueID()); 847 848 // Placeholders are never unrolled by SkCanvas (while other small pictures may be). 849 SkPictureRecorder recorder; 850 SkCanvas* canvas = recorder.beginRecording(cull); 851 canvas->drawPicture(p1); 852 canvas->drawPicture(p2); 853 sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture(); 854 REPORTER_ASSERT(r, pic->approximateOpCount() == 2); 855 } 856 857 DEF_TEST(Picture_empty_serial, reporter) { 858 SkPictureRecorder rec; 859 (void)rec.beginRecording(10, 10); 860 auto pic = rec.finishRecordingAsPicture(); 861 REPORTER_ASSERT(reporter, pic); 862 863 auto data = pic->serialize(); 864 REPORTER_ASSERT(reporter, data); 865 866 auto pic2 = SkPicture::MakeFromData(data->data(), data->size()); 867 REPORTER_ASSERT(reporter, pic2); 868 } 869 870