Home | History | Annotate | Download | only in tests
      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  *                                         const TestData& d,
     22  *                                         skiatest::Reporter* reporter,
     23  *                                         CanvasTestStep* testStep)
     24  *          {
     25  *              canvas->someCanvasAPImethod();
     26  *              (...)
     27  *              REPORTER_ASSERT_MESSAGE(reporter, (...), \
     28  *                  testStep->assertMessage());
     29  *          }
     30  *
     31  *      The definition of the test step function should be followed by an
     32  *      invocation of the TEST_STEP macro, which generates a class and
     33  *      instance for the test step:
     34  *
     35  *          TEST_STEP(MyTestStep, MyTestStepFunction)
     36  *
     37  *      There are also short hand macros for defining simple test steps
     38  *      in a single line of code.  A simple test step is a one that is made
     39  *      of a single canvas API call.
     40  *
     41  *          SIMPLE_TEST_STEP(MytestStep, someCanvasAPIMethod());
     42  *
     43  *      There is another macro called SIMPLE_TEST_STEP_WITH_ASSERT that
     44  *      works the same way as SIMPLE_TEST_STEP, and additionally verifies
     45  *      that the invoked method returns a non-zero value.
     46  */
     47 
     48 #include "SkBitmap.h"
     49 #include "SkCanvas.h"
     50 #include "SkClipStack.h"
     51 #include "SkDocument.h"
     52 #include "SkMatrix.h"
     53 #include "SkNWayCanvas.h"
     54 #include "SkPaint.h"
     55 #include "SkPaintFilterCanvas.h"
     56 #include "SkPath.h"
     57 #include "SkPicture.h"
     58 #include "SkPictureRecord.h"
     59 #include "SkPictureRecorder.h"
     60 #include "SkRasterClip.h"
     61 #include "SkRect.h"
     62 #include "SkRegion.h"
     63 #include "SkShader.h"
     64 #include "SkStream.h"
     65 #include "SkSurface.h"
     66 #include "SkTemplates.h"
     67 #include "SkTDArray.h"
     68 #include "SkVertices.h"
     69 #include "Test.h"
     70 
     71 DEF_TEST(canvas_clipbounds, reporter) {
     72     SkCanvas canvas(10, 10);
     73     SkIRect irect, irect2;
     74     SkRect rect, rect2;
     75 
     76     irect = canvas.getDeviceClipBounds();
     77     REPORTER_ASSERT(reporter, irect == SkIRect::MakeWH(10, 10));
     78     REPORTER_ASSERT(reporter, canvas.getDeviceClipBounds(&irect2));
     79     REPORTER_ASSERT(reporter, irect == irect2);
     80 
     81     // local bounds are always too big today -- can we trim them?
     82     rect = canvas.getLocalClipBounds();
     83     REPORTER_ASSERT(reporter, rect.contains(SkRect::MakeWH(10, 10)));
     84     REPORTER_ASSERT(reporter, canvas.getLocalClipBounds(&rect2));
     85     REPORTER_ASSERT(reporter, rect == rect2);
     86 
     87     canvas.clipRect(SkRect::MakeEmpty());
     88 
     89     irect = canvas.getDeviceClipBounds();
     90     REPORTER_ASSERT(reporter, irect == SkIRect::MakeEmpty());
     91     REPORTER_ASSERT(reporter, !canvas.getDeviceClipBounds(&irect2));
     92     REPORTER_ASSERT(reporter, irect == irect2);
     93 
     94     rect = canvas.getLocalClipBounds();
     95     REPORTER_ASSERT(reporter, rect == SkRect::MakeEmpty());
     96     REPORTER_ASSERT(reporter, !canvas.getLocalClipBounds(&rect2));
     97     REPORTER_ASSERT(reporter, rect == rect2);
     98 
     99     // Test for wacky sizes that we (historically) have guarded against
    100     {
    101         SkCanvas c(-10, -20);
    102         REPORTER_ASSERT(reporter, c.getBaseLayerSize() == SkISize::MakeEmpty());
    103 
    104         SkPictureRecorder().beginRecording({ 5, 5, 4, 4 });
    105     }
    106 }
    107 
    108 // Will call proc with multiple styles of canse (recording, raster, pdf)
    109 //
    110 template <typename F> static void multi_canvas_driver(int w, int h, F proc) {
    111     proc(SkPictureRecorder().beginRecording(SkRect::MakeIWH(w, h)));
    112 
    113     SkNullWStream stream;
    114     proc(SkDocument::MakePDF(&stream)->beginPage(SkIntToScalar(w), SkIntToScalar(h)));
    115 
    116     proc(SkSurface::MakeRasterN32Premul(w, h, nullptr)->getCanvas());
    117 }
    118 
    119 
    120 const SkIRect gBaseRestrictedR = { 0, 0, 10, 10 };
    121 
    122 static void test_restriction(skiatest::Reporter* reporter, SkCanvas* canvas) {
    123     REPORTER_ASSERT(reporter, canvas->getDeviceClipBounds() == gBaseRestrictedR);
    124 
    125     const SkIRect restrictionR = { 2, 2, 8, 8 };
    126     canvas->androidFramework_setDeviceClipRestriction(restrictionR);
    127     REPORTER_ASSERT(reporter, canvas->getDeviceClipBounds() == restrictionR);
    128 
    129     const SkIRect clipR = { 4, 4, 6, 6 };
    130     canvas->clipRect(SkRect::Make(clipR), SkClipOp::kIntersect);
    131     REPORTER_ASSERT(reporter, canvas->getDeviceClipBounds() == clipR);
    132 
    133 #ifdef SK_SUPPORT_DEPRECATED_CLIPOPS
    134     // now test that expanding clipops can't exceed the restriction
    135     const SkClipOp expanders[] = {
    136         SkClipOp::kUnion_deprecated,
    137         SkClipOp::kXOR_deprecated,
    138         SkClipOp::kReverseDifference_deprecated,
    139         SkClipOp::kReplace_deprecated,
    140     };
    141 
    142     const SkRect expandR = { 0, 0, 5, 9 };
    143     SkASSERT(!SkRect::Make(restrictionR).contains(expandR));
    144 
    145     for (SkClipOp op : expanders) {
    146         canvas->save();
    147         canvas->clipRect(expandR, op);
    148         REPORTER_ASSERT(reporter, gBaseRestrictedR.contains(canvas->getDeviceClipBounds()));
    149         canvas->restore();
    150     }
    151 #endif
    152 }
    153 
    154 /**
    155  *  Clip restriction logic exists in the canvas itself, and in various kinds of devices.
    156  *
    157  *  This test explicitly tries to exercise that variety:
    158  *  - picture : empty device but exercises canvas itself
    159  *  - pdf : uses SkClipStack in its device (as does SVG and GPU)
    160  *  - raster : uses SkRasterClip in its device
    161  */
    162 DEF_TEST(canvas_clip_restriction, reporter) {
    163     multi_canvas_driver(gBaseRestrictedR.width(), gBaseRestrictedR.height(),
    164                         [reporter](SkCanvas* canvas) { test_restriction(reporter, canvas); });
    165 }
    166 
    167 DEF_TEST(canvas_empty_clip, reporter) {
    168     multi_canvas_driver(50, 50, [reporter](SkCanvas* canvas) {
    169         canvas->save();
    170         canvas->clipRect({0, 0, 20, 40 });
    171         REPORTER_ASSERT(reporter, !canvas->isClipEmpty());
    172         canvas->clipRect({30, 0, 50, 40 });
    173         REPORTER_ASSERT(reporter, canvas->isClipEmpty());
    174     });
    175 }
    176 
    177 static const int kWidth = 2, kHeight = 2;
    178 
    179 static void createBitmap(SkBitmap* bm, SkColor color) {
    180     bm->allocN32Pixels(kWidth, kHeight);
    181     bm->eraseColor(color);
    182 }
    183 
    184 ///////////////////////////////////////////////////////////////////////////////
    185 // Constants used by test steps
    186 const SkPoint kTestPoints[] = {
    187     {SkIntToScalar(0), SkIntToScalar(0)},
    188     {SkIntToScalar(2), SkIntToScalar(1)},
    189     {SkIntToScalar(0), SkIntToScalar(2)}
    190 };
    191 const SkPoint kTestPoints2[] = {
    192     { SkIntToScalar(0), SkIntToScalar(1) },
    193     { SkIntToScalar(1), SkIntToScalar(1) },
    194     { SkIntToScalar(2), SkIntToScalar(1) },
    195     { SkIntToScalar(3), SkIntToScalar(1) },
    196     { SkIntToScalar(4), SkIntToScalar(1) },
    197     { SkIntToScalar(5), SkIntToScalar(1) },
    198     { SkIntToScalar(6), SkIntToScalar(1) },
    199     { SkIntToScalar(7), SkIntToScalar(1) },
    200     { SkIntToScalar(8), SkIntToScalar(1) },
    201     { SkIntToScalar(9), SkIntToScalar(1) },
    202     { SkIntToScalar(10), SkIntToScalar(1) }
    203 };
    204 
    205 struct TestData {
    206 public:
    207     TestData()
    208     : fRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
    209                                  SkIntToScalar(2), SkIntToScalar(1)))
    210     , fMatrix(TestMatrix())
    211     , fPath(TestPath())
    212     , fNearlyZeroLengthPath(TestNearlyZeroLengthPath())
    213     , fIRect(SkIRect::MakeXYWH(0, 0, 2, 1))
    214     , fRegion(TestRegion())
    215     , fColor(0x01020304)
    216     , fPoints(kTestPoints)
    217     , fPointCount(3)
    218     , fWidth(2)
    219     , fHeight(2)
    220     , fText("Hello World")
    221     , fPoints2(kTestPoints2)
    222     , fBitmap(TestBitmap())
    223     { }
    224 
    225     SkRect fRect;
    226     SkMatrix fMatrix;
    227     SkPath fPath;
    228     SkPath fNearlyZeroLengthPath;
    229     SkIRect fIRect;
    230     SkRegion fRegion;
    231     SkColor fColor;
    232     SkPaint fPaint;
    233     const SkPoint* fPoints;
    234     size_t fPointCount;
    235     int fWidth;
    236     int fHeight;
    237     SkString fText;
    238     const SkPoint* fPoints2;
    239     SkBitmap fBitmap;
    240 
    241 private:
    242     static SkMatrix TestMatrix() {
    243         SkMatrix matrix;
    244         matrix.reset();
    245         matrix.setScale(SkIntToScalar(2), SkIntToScalar(3));
    246 
    247         return matrix;
    248     }
    249     static SkPath TestPath() {
    250         SkPath path;
    251         path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
    252                                       SkIntToScalar(2), SkIntToScalar(1)));
    253         return path;
    254     }
    255     static SkPath TestNearlyZeroLengthPath() {
    256         SkPath path;
    257         SkPoint pt1 = { 0, 0 };
    258         SkPoint pt2 = { 0, SK_ScalarNearlyZero };
    259         SkPoint pt3 = { SkIntToScalar(1), 0 };
    260         SkPoint pt4 = { SkIntToScalar(1), SK_ScalarNearlyZero/2 };
    261         path.moveTo(pt1);
    262         path.lineTo(pt2);
    263         path.lineTo(pt3);
    264         path.lineTo(pt4);
    265         return path;
    266     }
    267     static SkRegion TestRegion() {
    268         SkRegion region;
    269         SkIRect rect = SkIRect::MakeXYWH(0, 0, 2, 1);
    270         region.setRect(rect);
    271         return region;
    272     }
    273     static SkBitmap TestBitmap() {
    274         SkBitmap bitmap;
    275         createBitmap(&bitmap, 0x05060708);
    276         return bitmap;
    277     }
    278 };
    279 
    280 // Format strings that describe the test context.  The %s token is where
    281 // the name of the test step is inserted.  The context is required for
    282 // disambiguating the error in the case of failures that are reported in
    283 // functions that are called multiple times in different contexts (test
    284 // cases and test steps).
    285 static const char* const kDefaultAssertMessageFormat = "%s";
    286 static const char* const kCanvasDrawAssertMessageFormat =
    287     "Drawing test step %s with SkCanvas";
    288 static const char* const kPdfAssertMessageFormat =
    289     "PDF sanity check failed %s";
    290 
    291 class CanvasTestStep;
    292 static SkTDArray<CanvasTestStep*>& testStepArray() {
    293     static SkTDArray<CanvasTestStep*> theTests;
    294     return theTests;
    295 }
    296 
    297 class CanvasTestStep {
    298 public:
    299     CanvasTestStep(bool fEnablePdfTesting = true) {
    300         *testStepArray().append() = this;
    301         fAssertMessageFormat = kDefaultAssertMessageFormat;
    302         this->fEnablePdfTesting = fEnablePdfTesting;
    303     }
    304     virtual ~CanvasTestStep() { }
    305 
    306     virtual void draw(SkCanvas*, const TestData&, skiatest::Reporter*) = 0;
    307     virtual const char* name() const = 0;
    308 
    309     const char* assertMessage() {
    310         fAssertMessage.printf(fAssertMessageFormat, name());
    311         return fAssertMessage.c_str();
    312     }
    313 
    314     void setAssertMessageFormat(const char* format) {
    315         fAssertMessageFormat = format;
    316     }
    317 
    318     bool enablePdfTesting() { return fEnablePdfTesting; }
    319 
    320 private:
    321     SkString fAssertMessage;
    322     const char* fAssertMessageFormat;
    323     bool fEnablePdfTesting;
    324 };
    325 
    326 ///////////////////////////////////////////////////////////////////////////////
    327 // Macros for defining test steps
    328 
    329 #define TEST_STEP(NAME, FUNCTION)                                       \
    330 class NAME##_TestStep : public CanvasTestStep{                          \
    331 public:                                                                 \
    332     virtual void draw(SkCanvas* canvas, const TestData& d,       \
    333         skiatest::Reporter* reporter) {                                 \
    334         FUNCTION (canvas, d, reporter, this);                    \
    335     }                                                                   \
    336     virtual const char* name() const {return #NAME ;}                   \
    337 };                                                                      \
    338 static NAME##_TestStep NAME##_TestStepInstance;
    339 
    340 #define TEST_STEP_NO_PDF(NAME, FUNCTION)                                \
    341 class NAME##_TestStep : public CanvasTestStep{                          \
    342 public:                                                                 \
    343     NAME##_TestStep() : CanvasTestStep(false) {}                        \
    344     virtual void draw(SkCanvas* canvas, const TestData& d,       \
    345         skiatest::Reporter* reporter) {                                 \
    346         FUNCTION (canvas, d, reporter, this);                    \
    347     }                                                                   \
    348     virtual const char* name() const {return #NAME ;}                   \
    349 };                                                                      \
    350 static NAME##_TestStep NAME##_TestStepInstance;
    351 
    352 #define SIMPLE_TEST_STEP(NAME, CALL)                                    \
    353 static void NAME##TestStep(SkCanvas* canvas, const TestData& d,  \
    354     skiatest::Reporter*, CanvasTestStep*) {                             \
    355     canvas-> CALL ;                                                     \
    356 }                                                                       \
    357 TEST_STEP(NAME, NAME##TestStep )
    358 
    359 #define SIMPLE_TEST_STEP_WITH_ASSERT(NAME, CALL)                           \
    360 static void NAME##TestStep(SkCanvas* canvas, const TestData& d,     \
    361     skiatest::Reporter*, CanvasTestStep* testStep) {                       \
    362     REPORTER_ASSERT_MESSAGE(reporter, canvas-> CALL ,                      \
    363         testStep->assertMessage());                                        \
    364 }                                                                          \
    365 TEST_STEP(NAME, NAME##TestStep )
    366 
    367 
    368 ///////////////////////////////////////////////////////////////////////////////
    369 // Basic test steps for most virtual methods in SkCanvas that draw or affect
    370 // the state of the canvas.
    371 
    372 SIMPLE_TEST_STEP(Translate, translate(SkIntToScalar(1), SkIntToScalar(2)));
    373 SIMPLE_TEST_STEP(Scale, scale(SkIntToScalar(1), SkIntToScalar(2)));
    374 SIMPLE_TEST_STEP(Rotate, rotate(SkIntToScalar(1)));
    375 SIMPLE_TEST_STEP(Skew, skew(SkIntToScalar(1), SkIntToScalar(2)));
    376 SIMPLE_TEST_STEP(Concat, concat(d.fMatrix));
    377 SIMPLE_TEST_STEP(SetMatrix, setMatrix(d.fMatrix));
    378 SIMPLE_TEST_STEP(ClipRect, clipRect(d.fRect));
    379 SIMPLE_TEST_STEP(ClipPath, clipPath(d.fPath));
    380 SIMPLE_TEST_STEP(ClipRegion, clipRegion(d.fRegion, kReplace_SkClipOp));
    381 SIMPLE_TEST_STEP(Clear, clear(d.fColor));
    382 
    383 ///////////////////////////////////////////////////////////////////////////////
    384 // Complex test steps
    385 
    386 static void SaveMatrixClipStep(SkCanvas* canvas, const TestData& d,
    387                                skiatest::Reporter* reporter, CanvasTestStep* testStep) {
    388     int saveCount = canvas->getSaveCount();
    389     canvas->save();
    390     canvas->translate(SkIntToScalar(1), SkIntToScalar(2));
    391     canvas->clipRegion(d.fRegion);
    392     canvas->restore();
    393     REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
    394         testStep->assertMessage());
    395     REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalMatrix().isIdentity(),
    396         testStep->assertMessage());
    397 //    REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalClip() != kTestRegion, testStep->assertMessage());
    398 }
    399 TEST_STEP(SaveMatrixClip, SaveMatrixClipStep);
    400 
    401 static void SaveLayerStep(SkCanvas* canvas, const TestData& d,
    402                           skiatest::Reporter* reporter, CanvasTestStep* testStep) {
    403     int saveCount = canvas->getSaveCount();
    404     canvas->saveLayer(nullptr, nullptr);
    405     canvas->restore();
    406     REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
    407         testStep->assertMessage());
    408 }
    409 TEST_STEP(SaveLayer, SaveLayerStep);
    410 
    411 static void BoundedSaveLayerStep(SkCanvas* canvas, const TestData& d,
    412                                  skiatest::Reporter* reporter, CanvasTestStep* testStep) {
    413     int saveCount = canvas->getSaveCount();
    414     canvas->saveLayer(&d.fRect, nullptr);
    415     canvas->restore();
    416     REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
    417         testStep->assertMessage());
    418 }
    419 TEST_STEP(BoundedSaveLayer, BoundedSaveLayerStep);
    420 
    421 static void PaintSaveLayerStep(SkCanvas* canvas, const TestData& d,
    422                                skiatest::Reporter* reporter, CanvasTestStep* testStep) {
    423     int saveCount = canvas->getSaveCount();
    424     canvas->saveLayer(nullptr, &d.fPaint);
    425     canvas->restore();
    426     REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
    427         testStep->assertMessage());
    428 }
    429 TEST_STEP(PaintSaveLayer, PaintSaveLayerStep);
    430 
    431 static void TwoClipOpsStep(SkCanvas* canvas, const TestData& d,
    432                            skiatest::Reporter*, CanvasTestStep*) {
    433     // This test exercises a functionality in SkPicture that leads to the
    434     // recording of restore offset placeholders.  This test will trigger an
    435     // assertion at playback time if the placeholders are not properly
    436     // filled when the recording ends.
    437     canvas->clipRect(d.fRect);
    438     canvas->clipRegion(d.fRegion);
    439 }
    440 TEST_STEP(TwoClipOps, TwoClipOpsStep);
    441 
    442 // exercise fix for http://code.google.com/p/skia/issues/detail?id=560
    443 // ('SkPathStroker::lineTo() fails for line with length SK_ScalarNearlyZero')
    444 static void DrawNearlyZeroLengthPathTestStep(SkCanvas* canvas, const TestData& d,
    445                                              skiatest::Reporter*, CanvasTestStep*) {
    446     SkPaint paint;
    447     paint.setStrokeWidth(SkIntToScalar(1));
    448     paint.setStyle(SkPaint::kStroke_Style);
    449 
    450     canvas->drawPath(d.fNearlyZeroLengthPath, paint);
    451 }
    452 TEST_STEP(DrawNearlyZeroLengthPath, DrawNearlyZeroLengthPathTestStep);
    453 
    454 static void DrawVerticesShaderTestStep(SkCanvas* canvas, const TestData& d,
    455                                        skiatest::Reporter*, CanvasTestStep*) {
    456     SkPoint pts[4];
    457     pts[0].set(0, 0);
    458     pts[1].set(SkIntToScalar(d.fWidth), 0);
    459     pts[2].set(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight));
    460     pts[3].set(0, SkIntToScalar(d.fHeight));
    461     SkPaint paint;
    462     paint.setShader(SkShader::MakeBitmapShader(d.fBitmap, SkShader::kClamp_TileMode,
    463                                                SkShader::kClamp_TileMode));
    464     canvas->drawVertices(SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4, pts, pts,
    465                                               nullptr),
    466                          SkBlendMode::kModulate, paint);
    467 }
    468 // NYI: issue 240.
    469 TEST_STEP_NO_PDF(DrawVerticesShader, DrawVerticesShaderTestStep);
    470 
    471 static void DrawPictureTestStep(SkCanvas* canvas, const TestData& d,
    472                                 skiatest::Reporter*, CanvasTestStep*) {
    473     SkPictureRecorder recorder;
    474     SkCanvas* testCanvas = recorder.beginRecording(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight),
    475                                                    nullptr, 0);
    476     testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1));
    477     testCanvas->clipRect(d.fRect);
    478     testCanvas->drawRect(d.fRect, d.fPaint);
    479 
    480     canvas->drawPicture(recorder.finishRecordingAsPicture());
    481 }
    482 TEST_STEP(DrawPicture, DrawPictureTestStep);
    483 
    484 static void SaveRestoreTestStep(SkCanvas* canvas, const TestData& d,
    485                                 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
    486     int baseSaveCount = canvas->getSaveCount();
    487     int n = canvas->save();
    488     REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount == n, testStep->assertMessage());
    489     REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
    490         testStep->assertMessage());
    491     canvas->save();
    492     canvas->save();
    493     REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 3 == canvas->getSaveCount(),
    494         testStep->assertMessage());
    495     canvas->restoreToCount(baseSaveCount + 1);
    496     REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
    497         testStep->assertMessage());
    498 
    499     // should this pin to 1, or be a no-op, or crash?
    500     canvas->restoreToCount(0);
    501     REPORTER_ASSERT_MESSAGE(reporter, 1 == canvas->getSaveCount(),
    502         testStep->assertMessage());
    503 }
    504 TEST_STEP(SaveRestore, SaveRestoreTestStep);
    505 
    506 static void NestedSaveRestoreWithSolidPaintTestStep(SkCanvas* canvas, const TestData& d,
    507                                                     skiatest::Reporter*, CanvasTestStep*) {
    508     // This test step challenges the TestDeferredCanvasStateConsistency
    509     // test cases because the opaque paint can trigger an optimization
    510     // that discards previously recorded commands. The challenge is to maintain
    511     // correct clip and matrix stack state.
    512     canvas->resetMatrix();
    513     canvas->rotate(SkIntToScalar(30));
    514     canvas->save();
    515     canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
    516     canvas->save();
    517     canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
    518     SkPaint paint;
    519     paint.setColor(0xFFFFFFFF);
    520     canvas->drawPaint(paint);
    521     canvas->restore();
    522     canvas->restore();
    523 }
    524 TEST_STEP(NestedSaveRestoreWithSolidPaint, \
    525     NestedSaveRestoreWithSolidPaintTestStep);
    526 
    527 static void NestedSaveRestoreWithFlushTestStep(SkCanvas* canvas, const TestData& d,
    528                                                skiatest::Reporter*, CanvasTestStep*) {
    529     // This test step challenges the TestDeferredCanvasStateConsistency
    530     // test case because the canvas flush on a deferred canvas will
    531     // reset the recording session. The challenge is to maintain correct
    532     // clip and matrix stack state on the playback canvas.
    533     canvas->resetMatrix();
    534     canvas->rotate(SkIntToScalar(30));
    535     canvas->save();
    536     canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
    537     canvas->save();
    538     canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
    539     canvas->drawRect(d.fRect,d.fPaint);
    540     canvas->flush();
    541     canvas->restore();
    542     canvas->restore();
    543 }
    544 TEST_STEP(NestedSaveRestoreWithFlush, NestedSaveRestoreWithFlushTestStep);
    545 
    546 static void TestPdfDevice(skiatest::Reporter* reporter, const TestData& d, CanvasTestStep* step) {
    547     SkDynamicMemoryWStream outStream;
    548     sk_sp<SkDocument> doc(SkDocument::MakePDF(&outStream));
    549     REPORTER_ASSERT(reporter, doc);
    550     if (!doc) {
    551         return;
    552     }
    553     SkCanvas* canvas = doc->beginPage(SkIntToScalar(d.fWidth),
    554                                       SkIntToScalar(d.fHeight));
    555     REPORTER_ASSERT(reporter, canvas);
    556     step->setAssertMessageFormat(kPdfAssertMessageFormat);
    557     step->draw(canvas, d, reporter);
    558 }
    559 
    560 /*
    561  * This sub-test verifies that the test step passes when executed
    562  * with SkCanvas and with classes derrived from SkCanvas. It also verifies
    563  * that the all canvas derivatives report the same state as an SkCanvas
    564  * after having executed the test step.
    565  */
    566 static void TestOverrideStateConsistency(skiatest::Reporter* reporter, const TestData& d,
    567                                          CanvasTestStep* testStep) {
    568     SkBitmap referenceStore;
    569     createBitmap(&referenceStore, 0xFFFFFFFF);
    570     SkCanvas referenceCanvas(referenceStore);
    571     testStep->setAssertMessageFormat(kCanvasDrawAssertMessageFormat);
    572     testStep->draw(&referenceCanvas, d, reporter);
    573 }
    574 
    575 static void test_newraster(skiatest::Reporter* reporter) {
    576     SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
    577     const size_t minRowBytes = info.minRowBytes();
    578     const size_t size = info.getSafeSize(minRowBytes);
    579     SkAutoTMalloc<SkPMColor> storage(size);
    580     SkPMColor* baseAddr = storage.get();
    581     sk_bzero(baseAddr, size);
    582 
    583     std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes);
    584     REPORTER_ASSERT(reporter, canvas);
    585 
    586     SkPixmap pmap;
    587     const SkPMColor* addr = canvas->peekPixels(&pmap) ? pmap.addr32() : nullptr;
    588     REPORTER_ASSERT(reporter, addr);
    589     REPORTER_ASSERT(reporter, info == pmap.info());
    590     REPORTER_ASSERT(reporter, minRowBytes == pmap.rowBytes());
    591     for (int y = 0; y < info.height(); ++y) {
    592         for (int x = 0; x < info.width(); ++x) {
    593             REPORTER_ASSERT(reporter, 0 == addr[x]);
    594         }
    595         addr = (const SkPMColor*)((const char*)addr + pmap.rowBytes());
    596     }
    597 
    598     // now try a deliberately bad info
    599     info = info.makeWH(-1, info.height());
    600     REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes));
    601 
    602     // too big
    603     info = info.makeWH(1 << 30, 1 << 30);
    604     REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes));
    605 
    606     // not a valid pixel type
    607     info = SkImageInfo::Make(10, 10, kUnknown_SkColorType, info.alphaType());
    608     REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes));
    609 
    610     // We should succeed with a zero-sized valid info
    611     info = SkImageInfo::MakeN32Premul(0, 0);
    612     canvas = SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes);
    613     REPORTER_ASSERT(reporter, canvas);
    614 }
    615 
    616 DEF_TEST(Canvas, reporter) {
    617     TestData d;
    618 
    619     for (int testStep = 0; testStep < testStepArray().count(); testStep++) {
    620         TestOverrideStateConsistency(reporter, d, testStepArray()[testStep]);
    621         if (testStepArray()[testStep]->enablePdfTesting()) {
    622             TestPdfDevice(reporter, d, testStepArray()[testStep]);
    623         }
    624     }
    625 
    626     test_newraster(reporter);
    627 }
    628 
    629 DEF_TEST(Canvas_SaveState, reporter) {
    630     SkCanvas canvas(10, 10);
    631     REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
    632 
    633     int n = canvas.save();
    634     REPORTER_ASSERT(reporter, 1 == n);
    635     REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
    636 
    637     n = canvas.saveLayer(nullptr, nullptr);
    638     REPORTER_ASSERT(reporter, 2 == n);
    639     REPORTER_ASSERT(reporter, 3 == canvas.getSaveCount());
    640 
    641     canvas.restore();
    642     REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
    643     canvas.restore();
    644     REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
    645 }
    646 
    647 DEF_TEST(Canvas_ClipEmptyPath, reporter) {
    648     SkCanvas canvas(10, 10);
    649     canvas.save();
    650     SkPath path;
    651     canvas.clipPath(path);
    652     canvas.restore();
    653     canvas.save();
    654     path.moveTo(5, 5);
    655     canvas.clipPath(path);
    656     canvas.restore();
    657     canvas.save();
    658     path.moveTo(7, 7);
    659     canvas.clipPath(path);  // should not assert here
    660     canvas.restore();
    661 }
    662 
    663 namespace {
    664 
    665 class MockFilterCanvas : public SkPaintFilterCanvas {
    666 public:
    667     MockFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) { }
    668 
    669 protected:
    670     bool onFilter(SkTCopyOnFirstWrite<SkPaint>*, Type) const override { return true; }
    671 
    672 private:
    673     typedef SkPaintFilterCanvas INHERITED;
    674 };
    675 
    676 } // anonymous namespace
    677 
    678 // SkPaintFilterCanvas should inherit the initial target canvas state.
    679 DEF_TEST(PaintFilterCanvas_ConsistentState, reporter) {
    680     SkCanvas canvas(100, 100);
    681     canvas.clipRect(SkRect::MakeXYWH(12.7f, 12.7f, 75, 75));
    682     canvas.scale(0.5f, 0.75f);
    683 
    684     MockFilterCanvas filterCanvas(&canvas);
    685     REPORTER_ASSERT(reporter, canvas.getTotalMatrix() == filterCanvas.getTotalMatrix());
    686     REPORTER_ASSERT(reporter, canvas.getLocalClipBounds() == filterCanvas.getLocalClipBounds());
    687 
    688     filterCanvas.clipRect(SkRect::MakeXYWH(30.5f, 30.7f, 100, 100));
    689     filterCanvas.scale(0.75f, 0.5f);
    690     REPORTER_ASSERT(reporter, canvas.getTotalMatrix() == filterCanvas.getTotalMatrix());
    691     REPORTER_ASSERT(reporter, filterCanvas.getLocalClipBounds().contains(canvas.getLocalClipBounds()));
    692 }
    693 
    694 ///////////////////////////////////////////////////////////////////////////////////////////////////
    695 
    696 #include "SkCanvasStack.h"
    697 #include "SkNWayCanvas.h"
    698 
    699 // Subclass that takes a bool*, which it updates in its construct (true) and destructor (false)
    700 // to allow the caller to know how long the object is alive.
    701 class LifeLineCanvas : public SkCanvas {
    702     bool*   fLifeLine;
    703 public:
    704     LifeLineCanvas(int w, int h, bool* lifeline) : SkCanvas(w, h), fLifeLine(lifeline) {
    705         *fLifeLine = true;
    706     }
    707     ~LifeLineCanvas() {
    708         *fLifeLine = false;
    709     }
    710 };
    711 
    712 // Check that NWayCanvas does NOT try to manage the lifetime of its sub-canvases
    713 DEF_TEST(NWayCanvas, r) {
    714     const int w = 10;
    715     const int h = 10;
    716     bool life[2];
    717     {
    718         LifeLineCanvas c0(w, h, &life[0]);
    719         REPORTER_ASSERT(r, life[0]);
    720     }
    721     REPORTER_ASSERT(r, !life[0]);
    722 
    723 
    724     std::unique_ptr<SkCanvas> c0 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[0]));
    725     std::unique_ptr<SkCanvas> c1 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[1]));
    726     REPORTER_ASSERT(r, life[0]);
    727     REPORTER_ASSERT(r, life[1]);
    728 
    729     {
    730         SkNWayCanvas nway(w, h);
    731         nway.addCanvas(c0.get());
    732         nway.addCanvas(c1.get());
    733         REPORTER_ASSERT(r, life[0]);
    734         REPORTER_ASSERT(r, life[1]);
    735     }
    736     // Now assert that the death of the nway has NOT also killed the sub-canvases
    737     REPORTER_ASSERT(r, life[0]);
    738     REPORTER_ASSERT(r, life[1]);
    739 }
    740 
    741 // Check that CanvasStack DOES manage the lifetime of its sub-canvases
    742 DEF_TEST(CanvasStack, r) {
    743     const int w = 10;
    744     const int h = 10;
    745     bool life[2];
    746     std::unique_ptr<SkCanvas> c0 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[0]));
    747     std::unique_ptr<SkCanvas> c1 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[1]));
    748     REPORTER_ASSERT(r, life[0]);
    749     REPORTER_ASSERT(r, life[1]);
    750 
    751     {
    752         SkCanvasStack stack(w, h);
    753         stack.pushCanvas(std::move(c0), {0,0});
    754         stack.pushCanvas(std::move(c1), {0,0});
    755         REPORTER_ASSERT(r, life[0]);
    756         REPORTER_ASSERT(r, life[1]);
    757     }
    758     // Now assert that the death of the canvasstack has also killed the sub-canvases
    759     REPORTER_ASSERT(r, !life[0]);
    760     REPORTER_ASSERT(r, !life[1]);
    761 }
    762 
    763 static void test_cliptype(SkCanvas* canvas, skiatest::Reporter* r) {
    764     REPORTER_ASSERT(r, !canvas->isClipEmpty());
    765     REPORTER_ASSERT(r, canvas->isClipRect());
    766 
    767     canvas->save();
    768     canvas->clipRect({0, 0, 0, 0});
    769     REPORTER_ASSERT(r, canvas->isClipEmpty());
    770     REPORTER_ASSERT(r, !canvas->isClipRect());
    771     canvas->restore();
    772 
    773     canvas->save();
    774     canvas->clipRect({2, 2, 6, 6});
    775     REPORTER_ASSERT(r, !canvas->isClipEmpty());
    776     REPORTER_ASSERT(r, canvas->isClipRect());
    777     canvas->restore();
    778 
    779     canvas->save();
    780     canvas->clipRect({2, 2, 6, 6}, SkClipOp::kDifference);  // punch a hole in the clip
    781     REPORTER_ASSERT(r, !canvas->isClipEmpty());
    782     REPORTER_ASSERT(r, !canvas->isClipRect());
    783     canvas->restore();
    784 
    785     REPORTER_ASSERT(r, !canvas->isClipEmpty());
    786     REPORTER_ASSERT(r, canvas->isClipRect());
    787 }
    788 
    789 DEF_TEST(CanvasClipType, r) {
    790     // test rasterclip backend
    791     test_cliptype(SkSurface::MakeRasterN32Premul(10, 10)->getCanvas(), r);
    792 
    793     // test clipstack backend
    794     SkDynamicMemoryWStream stream;
    795     test_cliptype(SkDocument::MakePDF(&stream)->beginPage(100, 100), r);
    796 }
    797 
    798 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
    799 DEF_TEST(Canvas_LegacyColorBehavior, r) {
    800     sk_sp<SkColorSpace> cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
    801                                                    SkColorSpace::kAdobeRGB_Gamut);
    802 
    803     // Make a Adobe RGB bitmap.
    804     SkBitmap bitmap;
    805     bitmap.allocPixels(SkImageInfo::MakeN32(1, 1, kOpaque_SkAlphaType, cs));
    806     bitmap.eraseColor(0xFF000000);
    807 
    808     // Wrap it in a legacy canvas.  Test that the canvas behaves like a legacy canvas.
    809     SkCanvas canvas(bitmap, SkCanvas::ColorBehavior::kLegacy);
    810     REPORTER_ASSERT(r, !canvas.imageInfo().colorSpace());
    811     SkPaint p;
    812     p.setColor(SK_ColorRED);
    813     canvas.drawIRect(SkIRect::MakeWH(1, 1), p);
    814     REPORTER_ASSERT(r, SK_ColorRED == SkSwizzle_BGRA_to_PMColor(*bitmap.getAddr32(0, 0)));
    815 }
    816 #endif
    817