CanvasTest.cpp revision 2ccdb636e8618db77be8e05cdacd82c249c6898c
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/* Description: 9 * This test defines a series of elementatry test steps that perform 10 * a single or a small group of canvas API calls. Each test step is 11 * used in several test cases that verify that different types of SkCanvas 12 * flavors and derivatives pass it and yield consistent behavior. The 13 * test cases analyse results that are queryable through the API. They do 14 * not look at rendering results. 15 * 16 * Adding test stepss: 17 * The general pattern for creating a new test step is to write a test 18 * function of the form: 19 * 20 * static void MyTestStepFunction(SkCanvas* canvas, 21 * skiatest::Reporter* reporter, 22 * CanvasTestStep* testStep) 23 * { 24 * canvas->someCanvasAPImethod(); 25 * (...) 26 * REPORTER_ASSERT_MESSAGE(reporter, (...), \ 27 * testStep->assertMessage()); 28 * } 29 * 30 * The definition of the test step function should be followed by an 31 * invocation of the TEST_STEP macro, which generates a class and 32 * instance for the test step: 33 * 34 * TEST_STEP(MyTestStep, MyTestStepFunction) 35 * 36 * There are also short hand macros for defining simple test steps 37 * in a single line of code. A simple test step is a one that is made 38 * of a single canvas API call. 39 * 40 * SIMPLE_TEST_STEP(MytestStep, someCanvasAPIMethod()); 41 * 42 * There is another macro called SIMPLE_TEST_STEP_WITH_ASSERT that 43 * works the same way as SIMPLE_TEST_STEP, and additionally verifies 44 * that the invoked method returns a non-zero value. 45 */ 46#include "SkBitmap.h" 47#include "SkCanvas.h" 48#include "SkClipStack.h" 49#include "SkDeferredCanvas.h" 50#include "SkDevice.h" 51#include "SkDocument.h" 52#include "SkMatrix.h" 53#include "SkNWayCanvas.h" 54#include "SkPaint.h" 55#include "SkPath.h" 56#include "SkPicture.h" 57#include "SkPictureRecord.h" 58#include "SkPictureRecorder.h" 59#include "SkRect.h" 60#include "SkRegion.h" 61#include "SkShader.h" 62#include "SkStream.h" 63#include "SkSurface.h" 64#include "SkTDArray.h" 65#include "Test.h" 66 67static const int kWidth = 2, kHeight = 2; 68 69static void createBitmap(SkBitmap* bm, SkColor color) { 70 bm->allocN32Pixels(kWidth, kHeight); 71 bm->eraseColor(color); 72} 73 74static SkSurface* createSurface(SkColor color) { 75 SkSurface* surface = SkSurface::NewRasterN32Premul(kWidth, kHeight); 76 surface->getCanvas()->clear(color); 77 return surface; 78} 79 80/////////////////////////////////////////////////////////////////////////////// 81// Constants used by test steps 82const SkPoint kTestPoints[] = { 83 {SkIntToScalar(0), SkIntToScalar(0)}, 84 {SkIntToScalar(2), SkIntToScalar(1)}, 85 {SkIntToScalar(0), SkIntToScalar(2)} 86}; 87const SkPoint kTestPoints2[] = { 88 { SkIntToScalar(0), SkIntToScalar(1) }, 89 { SkIntToScalar(1), SkIntToScalar(1) }, 90 { SkIntToScalar(2), SkIntToScalar(1) }, 91 { SkIntToScalar(3), SkIntToScalar(1) }, 92 { SkIntToScalar(4), SkIntToScalar(1) }, 93 { SkIntToScalar(5), SkIntToScalar(1) }, 94 { SkIntToScalar(6), SkIntToScalar(1) }, 95 { SkIntToScalar(7), SkIntToScalar(1) }, 96 { SkIntToScalar(8), SkIntToScalar(1) }, 97 { SkIntToScalar(9), SkIntToScalar(1) }, 98 { SkIntToScalar(10), SkIntToScalar(1) } 99}; 100 101struct TestData { 102public: 103 TestData() 104 : fRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 105 SkIntToScalar(2), SkIntToScalar(1))) 106 , fMatrix(TestMatrix()) 107 , fPath(TestPath()) 108 , fNearlyZeroLengthPath(TestNearlyZeroLengthPath()) 109 , fIRect(SkIRect::MakeXYWH(0, 0, 2, 1)) 110 , fRegion(TestRegion()) 111 , fColor(0x01020304) 112 , fPoints(kTestPoints) 113 , fPointCount(3) 114 , fWidth(2) 115 , fHeight(2) 116 , fText("Hello World") 117 , fPoints2(kTestPoints2) 118 , fBitmap(TestBitmap()) 119 { } 120 121 SkRect fRect; 122 SkMatrix fMatrix; 123 SkPath fPath; 124 SkPath fNearlyZeroLengthPath; 125 SkIRect fIRect; 126 SkRegion fRegion; 127 SkColor fColor; 128 SkPaint fPaint; 129 const SkPoint* fPoints; 130 size_t fPointCount; 131 int fWidth; 132 int fHeight; 133 SkString fText; 134 const SkPoint* fPoints2; 135 SkBitmap fBitmap; 136 137private: 138 static SkMatrix TestMatrix() { 139 SkMatrix matrix; 140 matrix.reset(); 141 matrix.setScale(SkIntToScalar(2), SkIntToScalar(3)); 142 143 return matrix; 144 } 145 static SkPath TestPath() { 146 SkPath path; 147 path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), 148 SkIntToScalar(2), SkIntToScalar(1))); 149 return path; 150 } 151 static SkPath TestNearlyZeroLengthPath() { 152 SkPath path; 153 SkPoint pt1 = { 0, 0 }; 154 SkPoint pt2 = { 0, SK_ScalarNearlyZero }; 155 SkPoint pt3 = { SkIntToScalar(1), 0 }; 156 SkPoint pt4 = { SkIntToScalar(1), SK_ScalarNearlyZero/2 }; 157 path.moveTo(pt1); 158 path.lineTo(pt2); 159 path.lineTo(pt3); 160 path.lineTo(pt4); 161 return path; 162 } 163 static SkRegion TestRegion() { 164 SkRegion region; 165 SkIRect rect = SkIRect::MakeXYWH(0, 0, 2, 1); 166 region.setRect(rect); 167 return region; 168 } 169 static SkBitmap TestBitmap() { 170 SkBitmap bitmap; 171 createBitmap(&bitmap, 0x05060708); 172 return bitmap; 173 } 174}; 175 176static bool equal_clips(const SkCanvas& a, const SkCanvas& b) { 177 if (a.isClipEmpty()) { 178 return b.isClipEmpty(); 179 } 180 if (!a.isClipRect()) { 181 // this is liberally true, since we don't expose a way to know this exactly (for non-rects) 182 return !b.isClipRect(); 183 } 184 SkIRect ar, br; 185 a.getClipDeviceBounds(&ar); 186 b.getClipDeviceBounds(&br); 187 return ar == br; 188} 189 190class Canvas2CanvasClipVisitor : public SkCanvas::ClipVisitor { 191public: 192 Canvas2CanvasClipVisitor(SkCanvas* target) : fTarget(target) {} 193 194 void clipRect(const SkRect& r, SkRegion::Op op, bool aa) override { 195 fTarget->clipRect(r, op, aa); 196 } 197 void clipRRect(const SkRRect& r, SkRegion::Op op, bool aa) override { 198 fTarget->clipRRect(r, op, aa); 199 } 200 void clipPath(const SkPath& p, SkRegion::Op op, bool aa) override { 201 fTarget->clipPath(p, op, aa); 202 } 203 204private: 205 SkCanvas* fTarget; 206}; 207 208static void test_clipVisitor(skiatest::Reporter* reporter, SkCanvas* canvas) { 209 SkISize size = canvas->getDeviceSize(); 210 211 SkBitmap bm; 212 bm.setInfo(SkImageInfo::MakeN32Premul(size.width(), size.height())); 213 SkCanvas c(bm); 214 215 Canvas2CanvasClipVisitor visitor(&c); 216 canvas->replayClips(&visitor); 217 218 REPORTER_ASSERT(reporter, equal_clips(c, *canvas)); 219} 220 221static void test_clipstack(skiatest::Reporter* reporter) { 222 // The clipstack is refcounted, and needs to be able to out-live the canvas if a client has 223 // ref'd it. 224 const SkClipStack* cs = NULL; 225 { 226 SkCanvas canvas(10, 10); 227 cs = SkRef(canvas.getClipStack()); 228 } 229 REPORTER_ASSERT(reporter, cs->unique()); 230 cs->unref(); 231} 232 233// Format strings that describe the test context. The %s token is where 234// the name of the test step is inserted. The context is required for 235// disambiguating the error in the case of failures that are reported in 236// functions that are called multiple times in different contexts (test 237// cases and test steps). 238static const char* const kDefaultAssertMessageFormat = "%s"; 239static const char* const kCanvasDrawAssertMessageFormat = 240 "Drawing test step %s with SkCanvas"; 241static const char* const kDeferredDrawAssertMessageFormat = 242 "Drawing test step %s with SkDeferredCanvas"; 243static const char* const kNWayDrawAssertMessageFormat = 244 "Drawing test step %s with SkNWayCanvas"; 245static const char* const kDeferredPreFlushAssertMessageFormat = 246 "test step %s, SkDeferredCanvas state consistency before flush"; 247static const char* const kDeferredPostFlushPlaybackAssertMessageFormat = 248 "test step %s, SkDeferredCanvas playback canvas state consistency after flush"; 249static const char* const kDeferredPostSilentFlushPlaybackAssertMessageFormat = 250 "test step %s, SkDeferredCanvas playback canvas state consistency after silent flush"; 251static const char* const kNWayStateAssertMessageFormat = 252 "test step %s, SkNWayCanvas state consistency"; 253static const char* const kNWayIndirect1StateAssertMessageFormat = 254 "test step %s, SkNWayCanvas indirect canvas 1 state consistency"; 255static const char* const kNWayIndirect2StateAssertMessageFormat = 256 "test step %s, SkNWayCanvas indirect canvas 2 state consistency"; 257static const char* const kPdfAssertMessageFormat = 258 "PDF sanity check failed %s"; 259 260class CanvasTestStep; 261static SkTDArray<CanvasTestStep*>& testStepArray() { 262 static SkTDArray<CanvasTestStep*> theTests; 263 return theTests; 264} 265 266class CanvasTestStep { 267public: 268 CanvasTestStep(bool fEnablePdfTesting = true) { 269 *testStepArray().append() = this; 270 fAssertMessageFormat = kDefaultAssertMessageFormat; 271 this->fEnablePdfTesting = fEnablePdfTesting; 272 } 273 virtual ~CanvasTestStep() { } 274 275 virtual void draw(SkCanvas*, const TestData&, skiatest::Reporter*) = 0; 276 virtual const char* name() const = 0; 277 278 const char* assertMessage() { 279 fAssertMessage.printf(fAssertMessageFormat, name()); 280 return fAssertMessage.c_str(); 281 } 282 283 void setAssertMessageFormat(const char* format) { 284 fAssertMessageFormat = format; 285 } 286 287 bool enablePdfTesting() { return fEnablePdfTesting; } 288 289private: 290 SkString fAssertMessage; 291 const char* fAssertMessageFormat; 292 bool fEnablePdfTesting; 293}; 294 295/////////////////////////////////////////////////////////////////////////////// 296// Macros for defining test steps 297 298#define TEST_STEP(NAME, FUNCTION) \ 299class NAME##_TestStep : public CanvasTestStep{ \ 300public: \ 301 virtual void draw(SkCanvas* canvas, const TestData& d, \ 302 skiatest::Reporter* reporter) { \ 303 FUNCTION (canvas, d, reporter, this); \ 304 } \ 305 virtual const char* name() const {return #NAME ;} \ 306}; \ 307static NAME##_TestStep NAME##_TestStepInstance; 308 309#define TEST_STEP_NO_PDF(NAME, FUNCTION) \ 310class NAME##_TestStep : public CanvasTestStep{ \ 311public: \ 312 NAME##_TestStep() : CanvasTestStep(false) {} \ 313 virtual void draw(SkCanvas* canvas, const TestData& d, \ 314 skiatest::Reporter* reporter) { \ 315 FUNCTION (canvas, d, reporter, this); \ 316 } \ 317 virtual const char* name() const {return #NAME ;} \ 318}; \ 319static NAME##_TestStep NAME##_TestStepInstance; 320 321#define SIMPLE_TEST_STEP(NAME, CALL) \ 322static void NAME##TestStep(SkCanvas* canvas, const TestData& d, \ 323 skiatest::Reporter*, CanvasTestStep*) { \ 324 canvas-> CALL ; \ 325} \ 326TEST_STEP(NAME, NAME##TestStep ) 327 328#define SIMPLE_TEST_STEP_WITH_ASSERT(NAME, CALL) \ 329static void NAME##TestStep(SkCanvas* canvas, const TestData& d, \ 330 skiatest::Reporter*, CanvasTestStep* testStep) { \ 331 REPORTER_ASSERT_MESSAGE(reporter, canvas-> CALL , \ 332 testStep->assertMessage()); \ 333} \ 334TEST_STEP(NAME, NAME##TestStep ) 335 336 337/////////////////////////////////////////////////////////////////////////////// 338// Basic test steps for most virtual methods in SkCanvas that draw or affect 339// the state of the canvas. 340 341SIMPLE_TEST_STEP(Translate, translate(SkIntToScalar(1), SkIntToScalar(2))); 342SIMPLE_TEST_STEP(Scale, scale(SkIntToScalar(1), SkIntToScalar(2))); 343SIMPLE_TEST_STEP(Rotate, rotate(SkIntToScalar(1))); 344SIMPLE_TEST_STEP(Skew, skew(SkIntToScalar(1), SkIntToScalar(2))); 345SIMPLE_TEST_STEP(Concat, concat(d.fMatrix)); 346SIMPLE_TEST_STEP(SetMatrix, setMatrix(d.fMatrix)); 347SIMPLE_TEST_STEP(ClipRect, clipRect(d.fRect)); 348SIMPLE_TEST_STEP(ClipPath, clipPath(d.fPath)); 349SIMPLE_TEST_STEP(ClipRegion, clipRegion(d.fRegion, SkRegion::kReplace_Op)); 350SIMPLE_TEST_STEP(Clear, clear(d.fColor)); 351 352/////////////////////////////////////////////////////////////////////////////// 353// Complex test steps 354 355static void SaveMatrixClipStep(SkCanvas* canvas, const TestData& d, 356 skiatest::Reporter* reporter, CanvasTestStep* testStep) { 357 int saveCount = canvas->getSaveCount(); 358 canvas->save(); 359 canvas->translate(SkIntToScalar(1), SkIntToScalar(2)); 360 canvas->clipRegion(d.fRegion); 361 canvas->restore(); 362 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount, 363 testStep->assertMessage()); 364 REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalMatrix().isIdentity(), 365 testStep->assertMessage()); 366// REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalClip() != kTestRegion, testStep->assertMessage()); 367} 368TEST_STEP(SaveMatrixClip, SaveMatrixClipStep); 369 370static void SaveLayerStep(SkCanvas* canvas, const TestData& d, 371 skiatest::Reporter* reporter, CanvasTestStep* testStep) { 372 int saveCount = canvas->getSaveCount(); 373 canvas->saveLayer(NULL, NULL); 374 canvas->restore(); 375 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount, 376 testStep->assertMessage()); 377} 378TEST_STEP(SaveLayer, SaveLayerStep); 379 380static void BoundedSaveLayerStep(SkCanvas* canvas, const TestData& d, 381 skiatest::Reporter* reporter, CanvasTestStep* testStep) { 382 int saveCount = canvas->getSaveCount(); 383 canvas->saveLayer(&d.fRect, NULL); 384 canvas->restore(); 385 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount, 386 testStep->assertMessage()); 387} 388TEST_STEP(BoundedSaveLayer, BoundedSaveLayerStep); 389 390static void PaintSaveLayerStep(SkCanvas* canvas, const TestData& d, 391 skiatest::Reporter* reporter, CanvasTestStep* testStep) { 392 int saveCount = canvas->getSaveCount(); 393 canvas->saveLayer(NULL, &d.fPaint); 394 canvas->restore(); 395 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount, 396 testStep->assertMessage()); 397} 398TEST_STEP(PaintSaveLayer, PaintSaveLayerStep); 399 400static void TwoClipOpsStep(SkCanvas* canvas, const TestData& d, 401 skiatest::Reporter*, CanvasTestStep*) { 402 // This test exercises a functionality in SkPicture that leads to the 403 // recording of restore offset placeholders. This test will trigger an 404 // assertion at playback time if the placeholders are not properly 405 // filled when the recording ends. 406 canvas->clipRect(d.fRect); 407 canvas->clipRegion(d.fRegion); 408} 409TEST_STEP(TwoClipOps, TwoClipOpsStep); 410 411// exercise fix for http://code.google.com/p/skia/issues/detail?id=560 412// ('SkPathStroker::lineTo() fails for line with length SK_ScalarNearlyZero') 413static void DrawNearlyZeroLengthPathTestStep(SkCanvas* canvas, const TestData& d, 414 skiatest::Reporter*, CanvasTestStep*) { 415 SkPaint paint; 416 paint.setStrokeWidth(SkIntToScalar(1)); 417 paint.setStyle(SkPaint::kStroke_Style); 418 419 canvas->drawPath(d.fNearlyZeroLengthPath, paint); 420} 421TEST_STEP(DrawNearlyZeroLengthPath, DrawNearlyZeroLengthPathTestStep); 422 423static void DrawVerticesShaderTestStep(SkCanvas* canvas, const TestData& d, 424 skiatest::Reporter*, CanvasTestStep*) { 425 SkPoint pts[4]; 426 pts[0].set(0, 0); 427 pts[1].set(SkIntToScalar(d.fWidth), 0); 428 pts[2].set(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight)); 429 pts[3].set(0, SkIntToScalar(d.fHeight)); 430 SkPaint paint; 431 SkShader* shader = SkShader::CreateBitmapShader(d.fBitmap, 432 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); 433 paint.setShader(shader)->unref(); 434 canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, pts, pts, 435 NULL, NULL, NULL, 0, paint); 436} 437// NYI: issue 240. 438TEST_STEP_NO_PDF(DrawVerticesShader, DrawVerticesShaderTestStep); 439 440static void DrawPictureTestStep(SkCanvas* canvas, const TestData& d, 441 skiatest::Reporter*, CanvasTestStep*) { 442 SkPictureRecorder recorder; 443 SkCanvas* testCanvas = recorder.beginRecording(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight), 444 NULL, 0); 445 testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1)); 446 testCanvas->clipRect(d.fRect); 447 testCanvas->drawRect(d.fRect, d.fPaint); 448 SkAutoTUnref<SkPicture> testPicture(recorder.endRecording()); 449 450 canvas->drawPicture(testPicture); 451} 452TEST_STEP(DrawPicture, DrawPictureTestStep); 453 454static void SaveRestoreTestStep(SkCanvas* canvas, const TestData& d, 455 skiatest::Reporter* reporter, CanvasTestStep* testStep) { 456 int baseSaveCount = canvas->getSaveCount(); 457 int n = canvas->save(); 458 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount == n, testStep->assertMessage()); 459 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(), 460 testStep->assertMessage()); 461 canvas->save(); 462 canvas->save(); 463 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 3 == canvas->getSaveCount(), 464 testStep->assertMessage()); 465 canvas->restoreToCount(baseSaveCount + 1); 466 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(), 467 testStep->assertMessage()); 468 469 // should this pin to 1, or be a no-op, or crash? 470 canvas->restoreToCount(0); 471 REPORTER_ASSERT_MESSAGE(reporter, 1 == canvas->getSaveCount(), 472 testStep->assertMessage()); 473} 474TEST_STEP(SaveRestore, SaveRestoreTestStep); 475 476static void NestedSaveRestoreWithSolidPaintTestStep(SkCanvas* canvas, const TestData& d, 477 skiatest::Reporter*, CanvasTestStep*) { 478 // This test step challenges the TestDeferredCanvasStateConsistency 479 // test cases because the opaque paint can trigger an optimization 480 // that discards previously recorded commands. The challenge is to maintain 481 // correct clip and matrix stack state. 482 canvas->resetMatrix(); 483 canvas->rotate(SkIntToScalar(30)); 484 canvas->save(); 485 canvas->translate(SkIntToScalar(2), SkIntToScalar(1)); 486 canvas->save(); 487 canvas->scale(SkIntToScalar(3), SkIntToScalar(3)); 488 SkPaint paint; 489 paint.setColor(0xFFFFFFFF); 490 canvas->drawPaint(paint); 491 canvas->restore(); 492 canvas->restore(); 493} 494TEST_STEP(NestedSaveRestoreWithSolidPaint, \ 495 NestedSaveRestoreWithSolidPaintTestStep); 496 497static void NestedSaveRestoreWithFlushTestStep(SkCanvas* canvas, const TestData& d, 498 skiatest::Reporter*, CanvasTestStep*) { 499 // This test step challenges the TestDeferredCanvasStateConsistency 500 // test case because the canvas flush on a deferred canvas will 501 // reset the recording session. The challenge is to maintain correct 502 // clip and matrix stack state on the playback canvas. 503 canvas->resetMatrix(); 504 canvas->rotate(SkIntToScalar(30)); 505 canvas->save(); 506 canvas->translate(SkIntToScalar(2), SkIntToScalar(1)); 507 canvas->save(); 508 canvas->scale(SkIntToScalar(3), SkIntToScalar(3)); 509 canvas->drawRect(d.fRect,d.fPaint); 510 canvas->flush(); 511 canvas->restore(); 512 canvas->restore(); 513} 514TEST_STEP(NestedSaveRestoreWithFlush, NestedSaveRestoreWithFlushTestStep); 515 516static void AssertCanvasStatesEqual(skiatest::Reporter* reporter, const TestData& d, 517 const SkCanvas* canvas1, const SkCanvas* canvas2, 518 CanvasTestStep* testStep) { 519 REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDeviceSize() == 520 canvas2->getDeviceSize(), testStep->assertMessage()); 521 REPORTER_ASSERT_MESSAGE(reporter, canvas1->getSaveCount() == 522 canvas2->getSaveCount(), testStep->assertMessage()); 523 524 SkRect bounds1, bounds2; 525 REPORTER_ASSERT_MESSAGE(reporter, 526 canvas1->getClipBounds(&bounds1) == canvas2->getClipBounds(&bounds2), 527 testStep->assertMessage()); 528 REPORTER_ASSERT_MESSAGE(reporter, bounds1 == bounds2, 529 testStep->assertMessage()); 530 531 REPORTER_ASSERT_MESSAGE(reporter, canvas1->getDrawFilter() == 532 canvas2->getDrawFilter(), testStep->assertMessage()); 533 SkIRect deviceBounds1, deviceBounds2; 534 REPORTER_ASSERT_MESSAGE(reporter, 535 canvas1->getClipDeviceBounds(&deviceBounds1) == 536 canvas2->getClipDeviceBounds(&deviceBounds2), 537 testStep->assertMessage()); 538 REPORTER_ASSERT_MESSAGE(reporter, deviceBounds1 == deviceBounds2, testStep->assertMessage()); 539 REPORTER_ASSERT_MESSAGE(reporter, canvas1->getTotalMatrix() == 540 canvas2->getTotalMatrix(), testStep->assertMessage()); 541 REPORTER_ASSERT_MESSAGE(reporter, equal_clips(*canvas1, *canvas2), testStep->assertMessage()); 542 543 SkCanvas::LayerIter layerIter1(const_cast<SkCanvas*>(canvas1), false); 544 SkCanvas::LayerIter layerIter2(const_cast<SkCanvas*>(canvas2), false); 545 while (!layerIter1.done() && !layerIter2.done()) { 546 REPORTER_ASSERT_MESSAGE(reporter, layerIter1.matrix() == 547 layerIter2.matrix(), testStep->assertMessage()); 548 REPORTER_ASSERT_MESSAGE(reporter, layerIter1.clip() == 549 layerIter2.clip(), testStep->assertMessage()); 550 REPORTER_ASSERT_MESSAGE(reporter, layerIter1.paint() == 551 layerIter2.paint(), testStep->assertMessage()); 552 REPORTER_ASSERT_MESSAGE(reporter, layerIter1.x() == 553 layerIter2.x(), testStep->assertMessage()); 554 REPORTER_ASSERT_MESSAGE(reporter, layerIter1.y() == 555 layerIter2.y(), testStep->assertMessage()); 556 layerIter1.next(); 557 layerIter2.next(); 558 } 559 REPORTER_ASSERT_MESSAGE(reporter, layerIter1.done(), 560 testStep->assertMessage()); 561 REPORTER_ASSERT_MESSAGE(reporter, layerIter2.done(), 562 testStep->assertMessage()); 563 564} 565 566static void TestPdfDevice(skiatest::Reporter* reporter, 567 const TestData& d, 568 CanvasTestStep* testStep) { 569 SkDynamicMemoryWStream outStream; 570 SkAutoTUnref<SkDocument> doc(SkDocument::CreatePDF(&outStream)); 571#if SK_SUPPORT_PDF 572 REPORTER_ASSERT(reporter, doc); 573#else 574 REPORTER_ASSERT(reporter, !doc); 575#endif // SK_SUPPORT_PDF 576 if (!doc) { 577 return; 578 } 579 SkCanvas* canvas = doc->beginPage(SkIntToScalar(d.fWidth), 580 SkIntToScalar(d.fHeight)); 581 REPORTER_ASSERT(reporter, canvas); 582 testStep->setAssertMessageFormat(kPdfAssertMessageFormat); 583 testStep->draw(canvas, d, reporter); 584 585 REPORTER_ASSERT(reporter, doc->close()); 586} 587 588// The following class groups static functions that need to access 589// the privates members of SkDeferredCanvas 590class SkDeferredCanvasTester { 591public: 592 static void TestDeferredCanvasStateConsistency( 593 skiatest::Reporter* reporter, 594 const TestData& d, 595 CanvasTestStep* testStep, 596 const SkCanvas& referenceCanvas, bool silent) { 597 598 SkAutoTUnref<SkSurface> surface(createSurface(0xFFFFFFFF)); 599 SkAutoTUnref<SkDeferredCanvas> deferredCanvas(SkDeferredCanvas::Create(surface.get())); 600 601 testStep->setAssertMessageFormat(kDeferredDrawAssertMessageFormat); 602 testStep->draw(deferredCanvas, d, reporter); 603 testStep->setAssertMessageFormat(kDeferredPreFlushAssertMessageFormat); 604 AssertCanvasStatesEqual(reporter, d, deferredCanvas, &referenceCanvas, testStep); 605 606 if (silent) { 607 deferredCanvas->silentFlush(); 608 } else { 609 deferredCanvas->flush(); 610 } 611 612 testStep->setAssertMessageFormat( 613 silent ? kDeferredPostSilentFlushPlaybackAssertMessageFormat : 614 kDeferredPostFlushPlaybackAssertMessageFormat); 615 AssertCanvasStatesEqual(reporter, d, deferredCanvas->immediateCanvas(), 616 &referenceCanvas, testStep); 617 618 // Verified that deferred canvas state is not affected by flushing 619 // pending draw operations 620 621 // The following test code is commented out because it currently fails. 622 // Issue: http://code.google.com/p/skia/issues/detail?id=496 623 /* 624 testStep->setAssertMessageFormat(kDeferredPostFlushAssertMessageFormat); 625 AssertCanvasStatesEqual(reporter, &deferredCanvas, &referenceCanvas, 626 testStep); 627 */ 628 } 629}; 630 631// unused 632static void TestNWayCanvasStateConsistency( 633 skiatest::Reporter* reporter, 634 const TestData& d, 635 CanvasTestStep* testStep, 636 const SkCanvas& referenceCanvas) { 637 638 SkBitmap indirectStore1; 639 createBitmap(&indirectStore1, 0xFFFFFFFF); 640 SkCanvas indirectCanvas1(indirectStore1); 641 642 SkBitmap indirectStore2; 643 createBitmap(&indirectStore2, 0xFFFFFFFF); 644 SkCanvas indirectCanvas2(indirectStore2); 645 646 SkISize canvasSize = referenceCanvas.getDeviceSize(); 647 SkNWayCanvas nWayCanvas(canvasSize.width(), canvasSize.height()); 648 nWayCanvas.addCanvas(&indirectCanvas1); 649 nWayCanvas.addCanvas(&indirectCanvas2); 650 651 testStep->setAssertMessageFormat(kNWayDrawAssertMessageFormat); 652 testStep->draw(&nWayCanvas, d, reporter); 653 // Verify that the SkNWayCanvas reports consitent state 654 testStep->setAssertMessageFormat(kNWayStateAssertMessageFormat); 655 AssertCanvasStatesEqual(reporter, d, &nWayCanvas, &referenceCanvas, testStep); 656 // Verify that the indirect canvases report consitent state 657 testStep->setAssertMessageFormat(kNWayIndirect1StateAssertMessageFormat); 658 AssertCanvasStatesEqual(reporter, d, &indirectCanvas1, &referenceCanvas, testStep); 659 testStep->setAssertMessageFormat(kNWayIndirect2StateAssertMessageFormat); 660 AssertCanvasStatesEqual(reporter, d, &indirectCanvas2, &referenceCanvas, testStep); 661} 662 663/* 664 * This sub-test verifies that the test step passes when executed 665 * with SkCanvas and with classes derrived from SkCanvas. It also verifies 666 * that the all canvas derivatives report the same state as an SkCanvas 667 * after having executed the test step. 668 */ 669static void TestOverrideStateConsistency(skiatest::Reporter* reporter, const TestData& d, 670 CanvasTestStep* testStep) { 671 SkBitmap referenceStore; 672 createBitmap(&referenceStore, 0xFFFFFFFF); 673 SkCanvas referenceCanvas(referenceStore); 674 testStep->setAssertMessageFormat(kCanvasDrawAssertMessageFormat); 675 testStep->draw(&referenceCanvas, d, reporter); 676 677 SkDeferredCanvasTester::TestDeferredCanvasStateConsistency(reporter, d, testStep, referenceCanvas, false); 678 679 SkDeferredCanvasTester::TestDeferredCanvasStateConsistency(reporter, d, testStep, referenceCanvas, true); 680 681 // The following test code is disabled because SkNWayCanvas does not 682 // report correct clipping and device bounds information 683 // Issue: http://code.google.com/p/skia/issues/detail?id=501 684 685 if (false) { // avoid bit rot, suppress warning 686 TestNWayCanvasStateConsistency(reporter, d, testStep, referenceCanvas); 687 } 688 689 if (false) { // avoid bit rot, suppress warning 690 test_clipVisitor(reporter, &referenceCanvas); 691 } 692 test_clipstack(reporter); 693} 694 695static void test_newraster(skiatest::Reporter* reporter) { 696 SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); 697 const size_t minRowBytes = info.minRowBytes(); 698 const size_t size = info.getSafeSize(minRowBytes); 699 SkAutoMalloc storage(size); 700 SkPMColor* baseAddr = static_cast<SkPMColor*>(storage.get()); 701 sk_bzero(baseAddr, size); 702 703 SkCanvas* canvas = SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes); 704 REPORTER_ASSERT(reporter, canvas); 705 706 SkImageInfo info2; 707 size_t rowBytes; 708 const SkPMColor* addr = (const SkPMColor*)canvas->peekPixels(&info2, &rowBytes); 709 REPORTER_ASSERT(reporter, addr); 710 REPORTER_ASSERT(reporter, info == info2); 711 REPORTER_ASSERT(reporter, minRowBytes == rowBytes); 712 for (int y = 0; y < info.height(); ++y) { 713 for (int x = 0; x < info.width(); ++x) { 714 REPORTER_ASSERT(reporter, 0 == addr[x]); 715 } 716 addr = (const SkPMColor*)((const char*)addr + rowBytes); 717 } 718 SkDELETE(canvas); 719 720 // now try a deliberately bad info 721 info = info.makeWH(-1, info.height()); 722 REPORTER_ASSERT(reporter, NULL == SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes)); 723 724 // too big 725 info = info.makeWH(1 << 30, 1 << 30); 726 REPORTER_ASSERT(reporter, NULL == SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes)); 727 728 // not a valid pixel type 729 info = SkImageInfo::Make(10, 10, kUnknown_SkColorType, info.alphaType()); 730 REPORTER_ASSERT(reporter, NULL == SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes)); 731 732 // We should succeed with a zero-sized valid info 733 info = SkImageInfo::MakeN32Premul(0, 0); 734 canvas = SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes); 735 REPORTER_ASSERT(reporter, canvas); 736 SkDELETE(canvas); 737} 738 739DEF_TEST(Canvas, reporter) { 740 TestData d; 741 742 for (int testStep = 0; testStep < testStepArray().count(); testStep++) { 743 TestOverrideStateConsistency(reporter, d, testStepArray()[testStep]); 744 if (testStepArray()[testStep]->enablePdfTesting()) { 745 TestPdfDevice(reporter, d, testStepArray()[testStep]); 746 } 747 } 748 749 test_newraster(reporter); 750} 751 752DEF_TEST(Canvas_SaveState, reporter) { 753 SkCanvas canvas(10, 10); 754 REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount()); 755 756 int n = canvas.save(); 757 REPORTER_ASSERT(reporter, 1 == n); 758 REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount()); 759 760 n = canvas.saveLayer(NULL, NULL); 761 REPORTER_ASSERT(reporter, 2 == n); 762 REPORTER_ASSERT(reporter, 3 == canvas.getSaveCount()); 763 764 canvas.restore(); 765 REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount()); 766 canvas.restore(); 767 REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount()); 768} 769 770DEF_TEST(Canvas_ClipEmptyPath, reporter) { 771 SkCanvas canvas(10, 10); 772 canvas.save(); 773 SkPath path; 774 canvas.clipPath(path); 775 canvas.restore(); 776 canvas.save(); 777 path.moveTo(5, 5); 778 canvas.clipPath(path); 779 canvas.restore(); 780 canvas.save(); 781 path.moveTo(7, 7); 782 canvas.clipPath(path); // should not assert here 783 canvas.restore(); 784} 785