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 "Test.h" 9 #include "TestClassDef.h" 10 #include "SkBitmapDevice.h" 11 #include "SkCanvas.h" 12 #include "SkColorPriv.h" 13 #include "SkData.h" 14 #include "SkDecodingImageGenerator.h" 15 #include "SkError.h" 16 #include "SkPaint.h" 17 #include "SkPicture.h" 18 #include "SkPictureUtils.h" 19 #include "SkRandom.h" 20 #include "SkRRect.h" 21 #include "SkShader.h" 22 #include "SkStream.h" 23 24 25 static void make_bm(SkBitmap* bm, int w, int h, SkColor color, bool immutable) { 26 bm->setConfig(SkBitmap::kARGB_8888_Config, w, h); 27 bm->allocPixels(); 28 bm->eraseColor(color); 29 if (immutable) { 30 bm->setImmutable(); 31 } 32 } 33 34 typedef void (*DrawBitmapProc)(SkCanvas*, const SkBitmap&, const SkPoint&); 35 36 static void drawbitmap_proc(SkCanvas* canvas, const SkBitmap& bm, 37 const SkPoint& pos) { 38 canvas->drawBitmap(bm, pos.fX, pos.fY, NULL); 39 } 40 41 static void drawbitmaprect_proc(SkCanvas* canvas, const SkBitmap& bm, 42 const SkPoint& pos) { 43 SkRect r = { 44 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) 45 }; 46 r.offset(pos.fX, pos.fY); 47 canvas->drawBitmapRectToRect(bm, NULL, r, NULL); 48 } 49 50 static void drawshader_proc(SkCanvas* canvas, const SkBitmap& bm, 51 const SkPoint& pos) { 52 SkRect r = { 53 0, 0, SkIntToScalar(bm.width()), SkIntToScalar(bm.height()) 54 }; 55 r.offset(pos.fX, pos.fY); 56 57 SkShader* s = SkShader::CreateBitmapShader(bm, 58 SkShader::kClamp_TileMode, 59 SkShader::kClamp_TileMode); 60 SkPaint paint; 61 paint.setShader(s)->unref(); 62 canvas->drawRect(r, paint); 63 canvas->drawOval(r, paint); 64 SkRRect rr; 65 rr.setRectXY(r, 10, 10); 66 canvas->drawRRect(rr, paint); 67 } 68 69 // Return a picture with the bitmaps drawn at the specified positions. 70 static SkPicture* record_bitmaps(const SkBitmap bm[], const SkPoint pos[], 71 int count, DrawBitmapProc proc) { 72 SkPicture* pic = new SkPicture; 73 SkCanvas* canvas = pic->beginRecording(1000, 1000); 74 for (int i = 0; i < count; ++i) { 75 proc(canvas, bm[i], pos[i]); 76 } 77 pic->endRecording(); 78 return pic; 79 } 80 81 static void rand_rect(SkRect* rect, SkRandom& rand, SkScalar W, SkScalar H) { 82 rect->fLeft = rand.nextRangeScalar(-W, 2*W); 83 rect->fTop = rand.nextRangeScalar(-H, 2*H); 84 rect->fRight = rect->fLeft + rand.nextRangeScalar(0, W); 85 rect->fBottom = rect->fTop + rand.nextRangeScalar(0, H); 86 87 // we integralize rect to make our tests more predictable, since Gather is 88 // a little sloppy. 89 SkIRect ir; 90 rect->round(&ir); 91 rect->set(ir); 92 } 93 94 // Allocate result to be large enough to hold subset, and then draw the picture 95 // into it, offsetting by subset's top/left corner. 96 static void draw(SkPicture* pic, const SkRect& subset, SkBitmap* result) { 97 SkIRect ir; 98 subset.roundOut(&ir); 99 int w = ir.width(); 100 int h = ir.height(); 101 make_bm(result, w, h, 0, false); 102 103 SkCanvas canvas(*result); 104 canvas.translate(-SkIntToScalar(ir.left()), -SkIntToScalar(ir.top())); 105 canvas.drawPicture(*pic); 106 } 107 108 template <typename T> int find_index(const T* array, T elem, int count) { 109 for (int i = 0; i < count; ++i) { 110 if (array[i] == elem) { 111 return i; 112 } 113 } 114 return -1; 115 } 116 117 // Return true if 'ref' is found in array[] 118 static bool find(SkPixelRef const * const * array, SkPixelRef const * ref, int count) { 119 return find_index<const SkPixelRef*>(array, ref, count) >= 0; 120 } 121 122 // Look at each pixel in bm, and if its color appears in colors[], find the 123 // corresponding value in refs[] and append that ref into array, skipping 124 // duplicates of the same value. 125 static void gather_from_colors(const SkBitmap& bm, SkPixelRef* const refs[], 126 int count, SkTDArray<SkPixelRef*>* array) { 127 // Since we only want to return unique values in array, when we scan we just 128 // set a bit for each index'd color found. In practice we only have a few 129 // distinct colors, so we just use an int's bits as our array. Hence the 130 // assert that count <= number-of-bits-in-our-int. 131 SkASSERT((unsigned)count <= 32); 132 uint32_t bitarray = 0; 133 134 SkAutoLockPixels alp(bm); 135 136 for (int y = 0; y < bm.height(); ++y) { 137 for (int x = 0; x < bm.width(); ++x) { 138 SkPMColor pmc = *bm.getAddr32(x, y); 139 // the only good case where the color is not found would be if 140 // the color is transparent, meaning no bitmap was drawn in that 141 // pixel. 142 if (pmc) { 143 uint32_t index = SkGetPackedR32(pmc); 144 SkASSERT(SkGetPackedG32(pmc) == index); 145 SkASSERT(SkGetPackedB32(pmc) == index); 146 SkASSERT(static_cast<int>(index) < count); 147 bitarray |= 1 << index; 148 } 149 } 150 } 151 152 for (int i = 0; i < count; ++i) { 153 if (bitarray & (1 << i)) { 154 *array->append() = refs[i]; 155 } 156 } 157 } 158 159 static void test_gatherpixelrefs(skiatest::Reporter* reporter) { 160 const int IW = 8; 161 const int IH = IW; 162 const SkScalar W = SkIntToScalar(IW); 163 const SkScalar H = W; 164 165 static const int N = 4; 166 SkBitmap bm[N]; 167 SkPixelRef* refs[N]; 168 169 const SkPoint pos[] = { 170 { 0, 0 }, { W, 0 }, { 0, H }, { W, H } 171 }; 172 173 // Our convention is that the color components contain the index of their 174 // corresponding bitmap/pixelref 175 for (int i = 0; i < N; ++i) { 176 make_bm(&bm[i], IW, IH, SkColorSetARGB(0xFF, i, i, i), true); 177 refs[i] = bm[i].pixelRef(); 178 } 179 180 static const DrawBitmapProc procs[] = { 181 drawbitmap_proc, drawbitmaprect_proc, drawshader_proc 182 }; 183 184 SkRandom rand; 185 for (size_t k = 0; k < SK_ARRAY_COUNT(procs); ++k) { 186 SkAutoTUnref<SkPicture> pic(record_bitmaps(bm, pos, N, procs[k])); 187 188 REPORTER_ASSERT(reporter, pic->willPlayBackBitmaps() || N == 0); 189 // quick check for a small piece of each quadrant, which should just 190 // contain 1 bitmap. 191 for (size_t i = 0; i < SK_ARRAY_COUNT(pos); ++i) { 192 SkRect r; 193 r.set(2, 2, W - 2, H - 2); 194 r.offset(pos[i].fX, pos[i].fY); 195 SkAutoDataUnref data(SkPictureUtils::GatherPixelRefs(pic, r)); 196 REPORTER_ASSERT(reporter, data); 197 if (data) { 198 int count = static_cast<int>(data->size() / sizeof(SkPixelRef*)); 199 REPORTER_ASSERT(reporter, 1 == count); 200 REPORTER_ASSERT(reporter, *(SkPixelRef**)data->data() == refs[i]); 201 } 202 } 203 204 // Test a bunch of random (mostly) rects, and compare the gather results 205 // with a deduced list of refs by looking at the colors drawn. 206 for (int j = 0; j < 100; ++j) { 207 SkRect r; 208 rand_rect(&r, rand, 2*W, 2*H); 209 210 SkBitmap result; 211 draw(pic, r, &result); 212 SkTDArray<SkPixelRef*> array; 213 214 SkData* data = SkPictureUtils::GatherPixelRefs(pic, r); 215 size_t dataSize = data ? data->size() : 0; 216 int gatherCount = static_cast<int>(dataSize / sizeof(SkPixelRef*)); 217 SkASSERT(gatherCount * sizeof(SkPixelRef*) == dataSize); 218 SkPixelRef** gatherRefs = data ? (SkPixelRef**)(data->data()) : NULL; 219 SkAutoDataUnref adu(data); 220 221 gather_from_colors(result, refs, N, &array); 222 223 /* 224 * GatherPixelRefs is conservative, so it can return more bitmaps 225 * that we actually can see (usually because of conservative bounds 226 * inflation for antialiasing). Thus our check here is only that 227 * Gather didn't miss any that we actually saw. Even that isn't 228 * a strict requirement on Gather, which is meant to be quick and 229 * only mostly-correct, but at the moment this test should work. 230 */ 231 for (int i = 0; i < array.count(); ++i) { 232 bool found = find(gatherRefs, array[i], gatherCount); 233 REPORTER_ASSERT(reporter, found); 234 #if 0 235 // enable this block of code to debug failures, as it will rerun 236 // the case that failed. 237 if (!found) { 238 SkData* data = SkPictureUtils::GatherPixelRefs(pic, r); 239 size_t dataSize = data ? data->size() : 0; 240 } 241 #endif 242 } 243 } 244 } 245 } 246 247 #ifdef SK_DEBUG 248 // Ensure that deleting SkPicturePlayback does not assert. Asserts only fire in debug mode, so only 249 // run in debug mode. 250 static void test_deleting_empty_playback() { 251 SkPicture picture; 252 // Creates an SkPictureRecord 253 picture.beginRecording(0, 0); 254 // Turns that into an SkPicturePlayback 255 picture.endRecording(); 256 // Deletes the old SkPicturePlayback, and creates a new SkPictureRecord 257 picture.beginRecording(0, 0); 258 } 259 260 // Ensure that serializing an empty picture does not assert. Likewise only runs in debug mode. 261 static void test_serializing_empty_picture() { 262 SkPicture picture; 263 picture.beginRecording(0, 0); 264 picture.endRecording(); 265 SkDynamicMemoryWStream stream; 266 picture.serialize(&stream); 267 } 268 #endif 269 270 static void rand_op(SkCanvas* canvas, SkRandom& rand) { 271 SkPaint paint; 272 SkRect rect = SkRect::MakeWH(50, 50); 273 274 SkScalar unit = rand.nextUScalar1(); 275 if (unit <= 0.3) { 276 // SkDebugf("save\n"); 277 canvas->save(); 278 } else if (unit <= 0.6) { 279 // SkDebugf("restore\n"); 280 canvas->restore(); 281 } else if (unit <= 0.9) { 282 // SkDebugf("clip\n"); 283 canvas->clipRect(rect); 284 } else { 285 // SkDebugf("draw\n"); 286 canvas->drawPaint(paint); 287 } 288 } 289 290 static void test_peephole() { 291 SkRandom rand; 292 293 for (int j = 0; j < 100; j++) { 294 SkRandom rand2(rand); // remember the seed 295 296 SkPicture picture; 297 SkCanvas* canvas = picture.beginRecording(100, 100); 298 299 for (int i = 0; i < 1000; ++i) { 300 rand_op(canvas, rand); 301 } 302 picture.endRecording(); 303 304 rand = rand2; 305 } 306 307 { 308 SkPicture picture; 309 SkCanvas* canvas = picture.beginRecording(100, 100); 310 SkRect rect = SkRect::MakeWH(50, 50); 311 312 for (int i = 0; i < 100; ++i) { 313 canvas->save(); 314 } 315 while (canvas->getSaveCount() > 1) { 316 canvas->clipRect(rect); 317 canvas->restore(); 318 } 319 picture.endRecording(); 320 } 321 } 322 323 #ifndef SK_DEBUG 324 // Only test this is in release mode. We deliberately crash in debug mode, since a valid caller 325 // should never do this. 326 static void test_bad_bitmap() { 327 // This bitmap has a width and height but no pixels. As a result, attempting to record it will 328 // fail. 329 SkBitmap bm; 330 bm.setConfig(SkBitmap::kARGB_8888_Config, 100, 100); 331 SkPicture picture; 332 SkCanvas* recordingCanvas = picture.beginRecording(100, 100); 333 recordingCanvas->drawBitmap(bm, 0, 0); 334 picture.endRecording(); 335 336 SkCanvas canvas; 337 canvas.drawPicture(picture); 338 } 339 #endif 340 341 #include "SkImageEncoder.h" 342 343 static SkData* encode_bitmap_to_data(size_t* offset, const SkBitmap& bm) { 344 *offset = 0; 345 return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100); 346 } 347 348 static SkData* serialized_picture_from_bitmap(const SkBitmap& bitmap) { 349 SkPicture picture; 350 SkCanvas* canvas = picture.beginRecording(bitmap.width(), bitmap.height()); 351 canvas->drawBitmap(bitmap, 0, 0); 352 SkDynamicMemoryWStream wStream; 353 picture.serialize(&wStream, &encode_bitmap_to_data); 354 return wStream.copyToData(); 355 } 356 357 struct ErrorContext { 358 int fErrors; 359 skiatest::Reporter* fReporter; 360 }; 361 362 static void assert_one_parse_error_cb(SkError error, void* context) { 363 ErrorContext* errorContext = static_cast<ErrorContext*>(context); 364 errorContext->fErrors++; 365 // This test only expects one error, and that is a kParseError. If there are others, 366 // there is some unknown problem. 367 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, 1 == errorContext->fErrors, 368 "This threw more errors than expected."); 369 REPORTER_ASSERT_MESSAGE(errorContext->fReporter, kParseError_SkError == error, 370 SkGetLastErrorString()); 371 } 372 373 static void test_bitmap_with_encoded_data(skiatest::Reporter* reporter) { 374 // Create a bitmap that will be encoded. 375 SkBitmap original; 376 make_bm(&original, 100, 100, SK_ColorBLUE, true); 377 SkDynamicMemoryWStream wStream; 378 if (!SkImageEncoder::EncodeStream(&wStream, original, SkImageEncoder::kPNG_Type, 100)) { 379 return; 380 } 381 SkAutoDataUnref data(wStream.copyToData()); 382 383 SkBitmap bm; 384 bool installSuccess = SkDecodingImageGenerator::Install(data, &bm); 385 REPORTER_ASSERT(reporter, installSuccess); 386 387 // Write both bitmaps to pictures, and ensure that the resulting data streams are the same. 388 // Flattening original will follow the old path of performing an encode, while flattening bm 389 // will use the already encoded data. 390 SkAutoDataUnref picture1(serialized_picture_from_bitmap(original)); 391 SkAutoDataUnref picture2(serialized_picture_from_bitmap(bm)); 392 REPORTER_ASSERT(reporter, picture1->equals(picture2)); 393 // Now test that a parse error was generated when trying to create a new SkPicture without 394 // providing a function to decode the bitmap. 395 ErrorContext context; 396 context.fErrors = 0; 397 context.fReporter = reporter; 398 SkSetErrorCallback(assert_one_parse_error_cb, &context); 399 SkMemoryStream pictureStream(picture1); 400 SkClearLastError(); 401 SkAutoUnref pictureFromStream(SkPicture::CreateFromStream(&pictureStream, NULL)); 402 REPORTER_ASSERT(reporter, pictureFromStream.get() != NULL); 403 SkClearLastError(); 404 SkSetErrorCallback(NULL, NULL); 405 } 406 407 static void test_clone_empty(skiatest::Reporter* reporter) { 408 // This is a regression test for crbug.com/172062 409 // Before the fix, we used to crash accessing a null pointer when we 410 // had a picture with no paints. This test passes by not crashing. 411 { 412 SkPicture picture; 413 picture.beginRecording(1, 1); 414 picture.endRecording(); 415 SkPicture* destPicture = picture.clone(); 416 REPORTER_ASSERT(reporter, NULL != destPicture); 417 destPicture->unref(); 418 } 419 { 420 // Test without call to endRecording 421 SkPicture picture; 422 picture.beginRecording(1, 1); 423 SkPicture* destPicture = picture.clone(); 424 REPORTER_ASSERT(reporter, NULL != destPicture); 425 destPicture->unref(); 426 } 427 } 428 429 static void test_clip_bound_opt(skiatest::Reporter* reporter) { 430 // Test for crbug.com/229011 431 SkRect rect1 = SkRect::MakeXYWH(SkIntToScalar(4), SkIntToScalar(4), 432 SkIntToScalar(2), SkIntToScalar(2)); 433 SkRect rect2 = SkRect::MakeXYWH(SkIntToScalar(7), SkIntToScalar(7), 434 SkIntToScalar(1), SkIntToScalar(1)); 435 SkRect rect3 = SkRect::MakeXYWH(SkIntToScalar(6), SkIntToScalar(6), 436 SkIntToScalar(1), SkIntToScalar(1)); 437 438 SkPath invPath; 439 invPath.addOval(rect1); 440 invPath.setFillType(SkPath::kInverseEvenOdd_FillType); 441 SkPath path; 442 path.addOval(rect2); 443 SkPath path2; 444 path2.addOval(rect3); 445 SkIRect clipBounds; 446 // Minimalist test set for 100% code coverage of 447 // SkPictureRecord::updateClipConservativelyUsingBounds 448 { 449 SkPicture picture; 450 SkCanvas* canvas = picture.beginRecording(10, 10, 451 SkPicture::kUsePathBoundsForClip_RecordingFlag); 452 canvas->clipPath(invPath, SkRegion::kIntersect_Op); 453 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds); 454 REPORTER_ASSERT(reporter, true == nonEmpty); 455 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft); 456 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop); 457 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom); 458 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight); 459 } 460 { 461 SkPicture picture; 462 SkCanvas* canvas = picture.beginRecording(10, 10, 463 SkPicture::kUsePathBoundsForClip_RecordingFlag); 464 canvas->clipPath(path, SkRegion::kIntersect_Op); 465 canvas->clipPath(invPath, SkRegion::kIntersect_Op); 466 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds); 467 REPORTER_ASSERT(reporter, true == nonEmpty); 468 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft); 469 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop); 470 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom); 471 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight); 472 } 473 { 474 SkPicture picture; 475 SkCanvas* canvas = picture.beginRecording(10, 10, 476 SkPicture::kUsePathBoundsForClip_RecordingFlag); 477 canvas->clipPath(path, SkRegion::kIntersect_Op); 478 canvas->clipPath(invPath, SkRegion::kUnion_Op); 479 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds); 480 REPORTER_ASSERT(reporter, true == nonEmpty); 481 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft); 482 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop); 483 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom); 484 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight); 485 } 486 { 487 SkPicture picture; 488 SkCanvas* canvas = picture.beginRecording(10, 10, 489 SkPicture::kUsePathBoundsForClip_RecordingFlag); 490 canvas->clipPath(path, SkRegion::kDifference_Op); 491 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds); 492 REPORTER_ASSERT(reporter, true == nonEmpty); 493 REPORTER_ASSERT(reporter, 0 == clipBounds.fLeft); 494 REPORTER_ASSERT(reporter, 0 == clipBounds.fTop); 495 REPORTER_ASSERT(reporter, 10 == clipBounds.fBottom); 496 REPORTER_ASSERT(reporter, 10 == clipBounds.fRight); 497 } 498 { 499 SkPicture picture; 500 SkCanvas* canvas = picture.beginRecording(10, 10, 501 SkPicture::kUsePathBoundsForClip_RecordingFlag); 502 canvas->clipPath(path, SkRegion::kReverseDifference_Op); 503 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds); 504 // True clip is actually empty in this case, but the best 505 // determination we can make using only bounds as input is that the 506 // clip is included in the bounds of 'path'. 507 REPORTER_ASSERT(reporter, true == nonEmpty); 508 REPORTER_ASSERT(reporter, 7 == clipBounds.fLeft); 509 REPORTER_ASSERT(reporter, 7 == clipBounds.fTop); 510 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom); 511 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight); 512 } 513 { 514 SkPicture picture; 515 SkCanvas* canvas = picture.beginRecording(10, 10, 516 SkPicture::kUsePathBoundsForClip_RecordingFlag); 517 canvas->clipPath(path, SkRegion::kIntersect_Op); 518 canvas->clipPath(path2, SkRegion::kXOR_Op); 519 bool nonEmpty = canvas->getClipDeviceBounds(&clipBounds); 520 REPORTER_ASSERT(reporter, true == nonEmpty); 521 REPORTER_ASSERT(reporter, 6 == clipBounds.fLeft); 522 REPORTER_ASSERT(reporter, 6 == clipBounds.fTop); 523 REPORTER_ASSERT(reporter, 8 == clipBounds.fBottom); 524 REPORTER_ASSERT(reporter, 8 == clipBounds.fRight); 525 } 526 } 527 528 /** 529 * A canvas that records the number of clip commands. 530 */ 531 class ClipCountingCanvas : public SkCanvas { 532 public: 533 explicit ClipCountingCanvas(SkBaseDevice* device) 534 : SkCanvas(device) 535 , fClipCount(0){ 536 } 537 538 virtual bool clipRect(const SkRect& r, SkRegion::Op op, bool doAA) 539 SK_OVERRIDE { 540 fClipCount += 1; 541 return this->INHERITED::clipRect(r, op, doAA); 542 } 543 544 virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) 545 SK_OVERRIDE { 546 fClipCount += 1; 547 return this->INHERITED::clipRRect(rrect, op, doAA); 548 } 549 550 virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAA) 551 SK_OVERRIDE { 552 fClipCount += 1; 553 return this->INHERITED::clipPath(path, op, doAA); 554 } 555 556 unsigned getClipCount() const { return fClipCount; } 557 558 private: 559 unsigned fClipCount; 560 561 typedef SkCanvas INHERITED; 562 }; 563 564 static void test_clip_expansion(skiatest::Reporter* reporter) { 565 SkPicture picture; 566 SkCanvas* canvas = picture.beginRecording(10, 10, 0); 567 568 canvas->clipRect(SkRect::MakeEmpty(), SkRegion::kReplace_Op); 569 // The following expanding clip should not be skipped. 570 canvas->clipRect(SkRect::MakeXYWH(4, 4, 3, 3), SkRegion::kUnion_Op); 571 // Draw something so the optimizer doesn't just fold the world. 572 SkPaint p; 573 p.setColor(SK_ColorBLUE); 574 canvas->drawPaint(p); 575 576 SkBitmapDevice testDevice(SkBitmap::kNo_Config, 10, 10); 577 ClipCountingCanvas testCanvas(&testDevice); 578 picture.draw(&testCanvas); 579 580 // Both clips should be present on playback. 581 REPORTER_ASSERT(reporter, testCanvas.getClipCount() == 2); 582 } 583 584 static void test_hierarchical(skiatest::Reporter* reporter) { 585 SkBitmap bm; 586 make_bm(&bm, 10, 10, SK_ColorRED, true); 587 588 SkCanvas* canvas; 589 590 SkPicture childPlain; 591 childPlain.beginRecording(10, 10); 592 childPlain.endRecording(); 593 REPORTER_ASSERT(reporter, !childPlain.willPlayBackBitmaps()); // 0 594 595 SkPicture childWithBitmap; 596 childWithBitmap.beginRecording(10, 10)->drawBitmap(bm, 0, 0); 597 childWithBitmap.endRecording(); 598 REPORTER_ASSERT(reporter, childWithBitmap.willPlayBackBitmaps()); // 1 599 600 SkPicture parentPP; 601 canvas = parentPP.beginRecording(10, 10); 602 canvas->drawPicture(childPlain); 603 parentPP.endRecording(); 604 REPORTER_ASSERT(reporter, !parentPP.willPlayBackBitmaps()); // 0 605 606 SkPicture parentPWB; 607 canvas = parentPWB.beginRecording(10, 10); 608 canvas->drawPicture(childWithBitmap); 609 parentPWB.endRecording(); 610 REPORTER_ASSERT(reporter, parentPWB.willPlayBackBitmaps()); // 1 611 612 SkPicture parentWBP; 613 canvas = parentWBP.beginRecording(10, 10); 614 canvas->drawBitmap(bm, 0, 0); 615 canvas->drawPicture(childPlain); 616 parentWBP.endRecording(); 617 REPORTER_ASSERT(reporter, parentWBP.willPlayBackBitmaps()); // 1 618 619 SkPicture parentWBWB; 620 canvas = parentWBWB.beginRecording(10, 10); 621 canvas->drawBitmap(bm, 0, 0); 622 canvas->drawPicture(childWithBitmap); 623 parentWBWB.endRecording(); 624 REPORTER_ASSERT(reporter, parentWBWB.willPlayBackBitmaps()); // 2 625 } 626 627 DEF_TEST(Picture, reporter) { 628 #ifdef SK_DEBUG 629 test_deleting_empty_playback(); 630 test_serializing_empty_picture(); 631 #else 632 test_bad_bitmap(); 633 #endif 634 test_peephole(); 635 test_gatherpixelrefs(reporter); 636 test_bitmap_with_encoded_data(reporter); 637 test_clone_empty(reporter); 638 test_clip_bound_opt(reporter); 639 test_clip_expansion(reporter); 640 test_hierarchical(reporter); 641 } 642