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