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