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