blob: b209d0df34a88a009ad771af1315bfac1523ba50 [file] [log] [blame]
reed@google.com37f3ae02011-11-28 16:06:04 +00001/*
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +00002 * Copyright 2012 Google Inc.
reed@google.com37f3ae02011-11-28 16:06:04 +00003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +00007
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 *
rmistry@google.comd6176b02012-08-23 18:14:13 +000020 * static void MyTestStepFunction(SkCanvas* canvas,
tomhudsoncb3bd182016-05-18 07:24:16 -070021 * const TestData& d,
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +000022 * 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 */
reed@google.com37f3ae02011-11-28 16:06:04 +000047#include "SkBitmap.h"
48#include "SkCanvas.h"
reed687fa1c2015-04-07 08:00:56 -070049#include "SkClipStack.h"
halcanary3d32d502015-03-01 06:55:20 -080050#include "SkDocument.h"
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +000051#include "SkMatrix.h"
52#include "SkNWayCanvas.h"
53#include "SkPaint.h"
fmalitaf433bb22015-08-17 08:05:13 -070054#include "SkPaintFilterCanvas.h"
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +000055#include "SkPath.h"
56#include "SkPicture.h"
57#include "SkPictureRecord.h"
robertphillips@google.com770963f2014-04-18 18:04:41 +000058#include "SkPictureRecorder.h"
reed1e7f5e72016-04-27 07:49:17 -070059#include "SkRasterClip.h"
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +000060#include "SkRect.h"
61#include "SkRegion.h"
62#include "SkShader.h"
63#include "SkStream.h"
reed@google.com28183b42014-02-04 15:34:10 +000064#include "SkSurface.h"
scroggo565901d2015-12-10 10:44:13 -080065#include "SkTemplates.h"
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +000066#include "SkTDArray.h"
67#include "Test.h"
reed@google.com37f3ae02011-11-28 16:06:04 +000068
piotaixrf05f5a72014-10-03 13:26:55 -070069static const int kWidth = 2, kHeight = 2;
70
71static void createBitmap(SkBitmap* bm, SkColor color) {
72 bm->allocN32Pixels(kWidth, kHeight);
73 bm->eraseColor(color);
74}
75
piotaixrf05f5a72014-10-03 13:26:55 -070076///////////////////////////////////////////////////////////////////////////////
77// Constants used by test steps
78const SkPoint kTestPoints[] = {
79 {SkIntToScalar(0), SkIntToScalar(0)},
80 {SkIntToScalar(2), SkIntToScalar(1)},
81 {SkIntToScalar(0), SkIntToScalar(2)}
82};
83const SkPoint kTestPoints2[] = {
84 { SkIntToScalar(0), SkIntToScalar(1) },
85 { SkIntToScalar(1), SkIntToScalar(1) },
86 { SkIntToScalar(2), SkIntToScalar(1) },
87 { SkIntToScalar(3), SkIntToScalar(1) },
88 { SkIntToScalar(4), SkIntToScalar(1) },
89 { SkIntToScalar(5), SkIntToScalar(1) },
90 { SkIntToScalar(6), SkIntToScalar(1) },
91 { SkIntToScalar(7), SkIntToScalar(1) },
92 { SkIntToScalar(8), SkIntToScalar(1) },
93 { SkIntToScalar(9), SkIntToScalar(1) },
94 { SkIntToScalar(10), SkIntToScalar(1) }
95};
96
97struct TestData {
98public:
99 TestData()
100 : fRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
101 SkIntToScalar(2), SkIntToScalar(1)))
102 , fMatrix(TestMatrix())
103 , fPath(TestPath())
104 , fNearlyZeroLengthPath(TestNearlyZeroLengthPath())
105 , fIRect(SkIRect::MakeXYWH(0, 0, 2, 1))
106 , fRegion(TestRegion())
107 , fColor(0x01020304)
108 , fPoints(kTestPoints)
109 , fPointCount(3)
110 , fWidth(2)
111 , fHeight(2)
112 , fText("Hello World")
113 , fPoints2(kTestPoints2)
114 , fBitmap(TestBitmap())
115 { }
116
117 SkRect fRect;
tfarina567ff2f2015-04-27 07:01:44 -0700118 SkMatrix fMatrix;
piotaixrf05f5a72014-10-03 13:26:55 -0700119 SkPath fPath;
120 SkPath fNearlyZeroLengthPath;
121 SkIRect fIRect;
122 SkRegion fRegion;
123 SkColor fColor;
124 SkPaint fPaint;
125 const SkPoint* fPoints;
126 size_t fPointCount;
127 int fWidth;
128 int fHeight;
129 SkString fText;
130 const SkPoint* fPoints2;
131 SkBitmap fBitmap;
132
133private:
134 static SkMatrix TestMatrix() {
135 SkMatrix matrix;
136 matrix.reset();
137 matrix.setScale(SkIntToScalar(2), SkIntToScalar(3));
138
139 return matrix;
140 }
141 static SkPath TestPath() {
142 SkPath path;
143 path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0),
144 SkIntToScalar(2), SkIntToScalar(1)));
145 return path;
146 }
147 static SkPath TestNearlyZeroLengthPath() {
148 SkPath path;
149 SkPoint pt1 = { 0, 0 };
150 SkPoint pt2 = { 0, SK_ScalarNearlyZero };
151 SkPoint pt3 = { SkIntToScalar(1), 0 };
152 SkPoint pt4 = { SkIntToScalar(1), SK_ScalarNearlyZero/2 };
153 path.moveTo(pt1);
154 path.lineTo(pt2);
155 path.lineTo(pt3);
156 path.lineTo(pt4);
157 return path;
158 }
159 static SkRegion TestRegion() {
160 SkRegion region;
161 SkIRect rect = SkIRect::MakeXYWH(0, 0, 2, 1);
162 region.setRect(rect);
163 return region;
164 }
165 static SkBitmap TestBitmap() {
166 SkBitmap bitmap;
167 createBitmap(&bitmap, 0x05060708);
168 return bitmap;
169 }
170};
171
reed@google.com90c07ea2012-04-13 13:50:27 +0000172class Canvas2CanvasClipVisitor : public SkCanvas::ClipVisitor {
173public:
174 Canvas2CanvasClipVisitor(SkCanvas* target) : fTarget(target) {}
175
mtklein36352bf2015-03-25 18:17:31 -0700176 void clipRect(const SkRect& r, SkRegion::Op op, bool aa) override {
reed@google.com90c07ea2012-04-13 13:50:27 +0000177 fTarget->clipRect(r, op, aa);
178 }
mtklein36352bf2015-03-25 18:17:31 -0700179 void clipRRect(const SkRRect& r, SkRegion::Op op, bool aa) override {
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000180 fTarget->clipRRect(r, op, aa);
181 }
mtklein36352bf2015-03-25 18:17:31 -0700182 void clipPath(const SkPath& p, SkRegion::Op op, bool aa) override {
reed@google.com90c07ea2012-04-13 13:50:27 +0000183 fTarget->clipPath(p, op, aa);
184 }
185
186private:
187 SkCanvas* fTarget;
188};
189
reed687fa1c2015-04-07 08:00:56 -0700190static void test_clipstack(skiatest::Reporter* reporter) {
191 // The clipstack is refcounted, and needs to be able to out-live the canvas if a client has
192 // ref'd it.
halcanary96fcdcc2015-08-27 07:41:13 -0700193 const SkClipStack* cs = nullptr;
reed687fa1c2015-04-07 08:00:56 -0700194 {
195 SkCanvas canvas(10, 10);
196 cs = SkRef(canvas.getClipStack());
197 }
198 REPORTER_ASSERT(reporter, cs->unique());
199 cs->unref();
200}
201
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000202// Format strings that describe the test context. The %s token is where
203// the name of the test step is inserted. The context is required for
204// disambiguating the error in the case of failures that are reported in
205// functions that are called multiple times in different contexts (test
206// cases and test steps).
207static const char* const kDefaultAssertMessageFormat = "%s";
rmistry@google.comd6176b02012-08-23 18:14:13 +0000208static const char* const kCanvasDrawAssertMessageFormat =
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000209 "Drawing test step %s with SkCanvas";
edisonn@google.com77909122012-10-18 15:58:23 +0000210static const char* const kPdfAssertMessageFormat =
211 "PDF sanity check failed %s";
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000212
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000213class CanvasTestStep;
214static SkTDArray<CanvasTestStep*>& testStepArray() {
215 static SkTDArray<CanvasTestStep*> theTests;
216 return theTests;
217}
218
219class CanvasTestStep {
220public:
edisonn@google.com77909122012-10-18 15:58:23 +0000221 CanvasTestStep(bool fEnablePdfTesting = true) {
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000222 *testStepArray().append() = this;
223 fAssertMessageFormat = kDefaultAssertMessageFormat;
edisonn@google.com77909122012-10-18 15:58:23 +0000224 this->fEnablePdfTesting = fEnablePdfTesting;
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000225 }
djsollen@google.come63793a2012-03-21 15:39:03 +0000226 virtual ~CanvasTestStep() { }
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000227
piotaixrf05f5a72014-10-03 13:26:55 -0700228 virtual void draw(SkCanvas*, const TestData&, skiatest::Reporter*) = 0;
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000229 virtual const char* name() const = 0;
230
231 const char* assertMessage() {
232 fAssertMessage.printf(fAssertMessageFormat, name());
233 return fAssertMessage.c_str();
234 }
235
236 void setAssertMessageFormat(const char* format) {
237 fAssertMessageFormat = format;
238 }
239
edisonn@google.com77909122012-10-18 15:58:23 +0000240 bool enablePdfTesting() { return fEnablePdfTesting; }
241
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000242private:
243 SkString fAssertMessage;
244 const char* fAssertMessageFormat;
edisonn@google.com77909122012-10-18 15:58:23 +0000245 bool fEnablePdfTesting;
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000246};
247
248///////////////////////////////////////////////////////////////////////////////
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000249// Macros for defining test steps
250
251#define TEST_STEP(NAME, FUNCTION) \
252class NAME##_TestStep : public CanvasTestStep{ \
253public: \
piotaixrf05f5a72014-10-03 13:26:55 -0700254 virtual void draw(SkCanvas* canvas, const TestData& d, \
255 skiatest::Reporter* reporter) { \
256 FUNCTION (canvas, d, reporter, this); \
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000257 } \
258 virtual const char* name() const {return #NAME ;} \
259}; \
260static NAME##_TestStep NAME##_TestStepInstance;
261
piotaixrf05f5a72014-10-03 13:26:55 -0700262#define TEST_STEP_NO_PDF(NAME, FUNCTION) \
edisonn@google.com77909122012-10-18 15:58:23 +0000263class NAME##_TestStep : public CanvasTestStep{ \
264public: \
265 NAME##_TestStep() : CanvasTestStep(false) {} \
piotaixrf05f5a72014-10-03 13:26:55 -0700266 virtual void draw(SkCanvas* canvas, const TestData& d, \
267 skiatest::Reporter* reporter) { \
268 FUNCTION (canvas, d, reporter, this); \
edisonn@google.com77909122012-10-18 15:58:23 +0000269 } \
270 virtual const char* name() const {return #NAME ;} \
271}; \
272static NAME##_TestStep NAME##_TestStepInstance;
273
piotaixrf05f5a72014-10-03 13:26:55 -0700274#define SIMPLE_TEST_STEP(NAME, CALL) \
275static void NAME##TestStep(SkCanvas* canvas, const TestData& d, \
276 skiatest::Reporter*, CanvasTestStep*) { \
277 canvas-> CALL ; \
278} \
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000279TEST_STEP(NAME, NAME##TestStep )
280
281#define SIMPLE_TEST_STEP_WITH_ASSERT(NAME, CALL) \
piotaixrf05f5a72014-10-03 13:26:55 -0700282static void NAME##TestStep(SkCanvas* canvas, const TestData& d, \
283 skiatest::Reporter*, CanvasTestStep* testStep) { \
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000284 REPORTER_ASSERT_MESSAGE(reporter, canvas-> CALL , \
285 testStep->assertMessage()); \
286} \
287TEST_STEP(NAME, NAME##TestStep )
288
289
290///////////////////////////////////////////////////////////////////////////////
rmistry@google.comd6176b02012-08-23 18:14:13 +0000291// Basic test steps for most virtual methods in SkCanvas that draw or affect
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000292// the state of the canvas.
293
commit-bot@chromium.org92362382014-03-18 12:51:48 +0000294SIMPLE_TEST_STEP(Translate, translate(SkIntToScalar(1), SkIntToScalar(2)));
295SIMPLE_TEST_STEP(Scale, scale(SkIntToScalar(1), SkIntToScalar(2)));
296SIMPLE_TEST_STEP(Rotate, rotate(SkIntToScalar(1)));
297SIMPLE_TEST_STEP(Skew, skew(SkIntToScalar(1), SkIntToScalar(2)));
piotaixrf05f5a72014-10-03 13:26:55 -0700298SIMPLE_TEST_STEP(Concat, concat(d.fMatrix));
299SIMPLE_TEST_STEP(SetMatrix, setMatrix(d.fMatrix));
300SIMPLE_TEST_STEP(ClipRect, clipRect(d.fRect));
301SIMPLE_TEST_STEP(ClipPath, clipPath(d.fPath));
302SIMPLE_TEST_STEP(ClipRegion, clipRegion(d.fRegion, SkRegion::kReplace_Op));
303SIMPLE_TEST_STEP(Clear, clear(d.fColor));
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000304
305///////////////////////////////////////////////////////////////////////////////
306// Complex test steps
307
piotaixrf05f5a72014-10-03 13:26:55 -0700308static void SaveMatrixClipStep(SkCanvas* canvas, const TestData& d,
309 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000310 int saveCount = canvas->getSaveCount();
Florin Malita5f6102d2014-06-30 10:13:28 -0400311 canvas->save();
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000312 canvas->translate(SkIntToScalar(1), SkIntToScalar(2));
piotaixrf05f5a72014-10-03 13:26:55 -0700313 canvas->clipRegion(d.fRegion);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000314 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000315 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000316 testStep->assertMessage());
rmistry@google.comd6176b02012-08-23 18:14:13 +0000317 REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalMatrix().isIdentity(),
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000318 testStep->assertMessage());
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +0000319// REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalClip() != kTestRegion, testStep->assertMessage());
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000320}
321TEST_STEP(SaveMatrixClip, SaveMatrixClipStep);
322
piotaixrf05f5a72014-10-03 13:26:55 -0700323static void SaveLayerStep(SkCanvas* canvas, const TestData& d,
324 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000325 int saveCount = canvas->getSaveCount();
halcanary96fcdcc2015-08-27 07:41:13 -0700326 canvas->saveLayer(nullptr, nullptr);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000327 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000328 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000329 testStep->assertMessage());
330}
331TEST_STEP(SaveLayer, SaveLayerStep);
332
piotaixrf05f5a72014-10-03 13:26:55 -0700333static void BoundedSaveLayerStep(SkCanvas* canvas, const TestData& d,
334 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000335 int saveCount = canvas->getSaveCount();
halcanary96fcdcc2015-08-27 07:41:13 -0700336 canvas->saveLayer(&d.fRect, nullptr);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000337 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000338 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000339 testStep->assertMessage());
340}
341TEST_STEP(BoundedSaveLayer, BoundedSaveLayerStep);
342
piotaixrf05f5a72014-10-03 13:26:55 -0700343static void PaintSaveLayerStep(SkCanvas* canvas, const TestData& d,
344 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000345 int saveCount = canvas->getSaveCount();
halcanary96fcdcc2015-08-27 07:41:13 -0700346 canvas->saveLayer(nullptr, &d.fPaint);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000347 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000348 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000349 testStep->assertMessage());
350}
351TEST_STEP(PaintSaveLayer, PaintSaveLayerStep);
352
piotaixrf05f5a72014-10-03 13:26:55 -0700353static void TwoClipOpsStep(SkCanvas* canvas, const TestData& d,
354 skiatest::Reporter*, CanvasTestStep*) {
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000355 // This test exercises a functionality in SkPicture that leads to the
rmistry@google.comd6176b02012-08-23 18:14:13 +0000356 // recording of restore offset placeholders. This test will trigger an
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000357 // assertion at playback time if the placeholders are not properly
358 // filled when the recording ends.
piotaixrf05f5a72014-10-03 13:26:55 -0700359 canvas->clipRect(d.fRect);
360 canvas->clipRegion(d.fRegion);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000361}
362TEST_STEP(TwoClipOps, TwoClipOpsStep);
363
epoger@google.com94fa43c2012-04-11 17:51:01 +0000364// exercise fix for http://code.google.com/p/skia/issues/detail?id=560
365// ('SkPathStroker::lineTo() fails for line with length SK_ScalarNearlyZero')
piotaixrf05f5a72014-10-03 13:26:55 -0700366static void DrawNearlyZeroLengthPathTestStep(SkCanvas* canvas, const TestData& d,
367 skiatest::Reporter*, CanvasTestStep*) {
epoger@google.com94fa43c2012-04-11 17:51:01 +0000368 SkPaint paint;
369 paint.setStrokeWidth(SkIntToScalar(1));
370 paint.setStyle(SkPaint::kStroke_Style);
371
piotaixrf05f5a72014-10-03 13:26:55 -0700372 canvas->drawPath(d.fNearlyZeroLengthPath, paint);
epoger@google.com94fa43c2012-04-11 17:51:01 +0000373}
374TEST_STEP(DrawNearlyZeroLengthPath, DrawNearlyZeroLengthPathTestStep);
375
piotaixrf05f5a72014-10-03 13:26:55 -0700376static void DrawVerticesShaderTestStep(SkCanvas* canvas, const TestData& d,
377 skiatest::Reporter*, CanvasTestStep*) {
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000378 SkPoint pts[4];
379 pts[0].set(0, 0);
piotaixrf05f5a72014-10-03 13:26:55 -0700380 pts[1].set(SkIntToScalar(d.fWidth), 0);
381 pts[2].set(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight));
382 pts[3].set(0, SkIntToScalar(d.fHeight));
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000383 SkPaint paint;
reed1a9b9642016-03-13 14:13:58 -0700384 paint.setShader(SkShader::MakeBitmapShader(d.fBitmap, SkShader::kClamp_TileMode,
385 SkShader::kClamp_TileMode));
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000386 canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, pts, pts,
halcanary96fcdcc2015-08-27 07:41:13 -0700387 nullptr, nullptr, nullptr, 0, paint);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000388}
edisonn@google.com77909122012-10-18 15:58:23 +0000389// NYI: issue 240.
390TEST_STEP_NO_PDF(DrawVerticesShader, DrawVerticesShaderTestStep);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000391
piotaixrf05f5a72014-10-03 13:26:55 -0700392static void DrawPictureTestStep(SkCanvas* canvas, const TestData& d,
393 skiatest::Reporter*, CanvasTestStep*) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000394 SkPictureRecorder recorder;
piotaixrf05f5a72014-10-03 13:26:55 -0700395 SkCanvas* testCanvas = recorder.beginRecording(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight),
halcanary96fcdcc2015-08-27 07:41:13 -0700396 nullptr, 0);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000397 testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1));
piotaixrf05f5a72014-10-03 13:26:55 -0700398 testCanvas->clipRect(d.fRect);
399 testCanvas->drawRect(d.fRect, d.fPaint);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000400
reedca2622b2016-03-18 07:25:55 -0700401 canvas->drawPicture(recorder.finishRecordingAsPicture());
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000402}
403TEST_STEP(DrawPicture, DrawPictureTestStep);
404
piotaixrf05f5a72014-10-03 13:26:55 -0700405static void SaveRestoreTestStep(SkCanvas* canvas, const TestData& d,
406 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000407 int baseSaveCount = canvas->getSaveCount();
tomhudson@google.com8afae612012-08-14 15:03:35 +0000408 int n = canvas->save();
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000409 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount == n, testStep->assertMessage());
410 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000411 testStep->assertMessage());
412 canvas->save();
413 canvas->save();
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000414 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 3 == canvas->getSaveCount(),
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000415 testStep->assertMessage());
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000416 canvas->restoreToCount(baseSaveCount + 1);
417 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000418 testStep->assertMessage());
419
420 // should this pin to 1, or be a no-op, or crash?
421 canvas->restoreToCount(0);
422 REPORTER_ASSERT_MESSAGE(reporter, 1 == canvas->getSaveCount(),
423 testStep->assertMessage());
424}
425TEST_STEP(SaveRestore, SaveRestoreTestStep);
426
piotaixrf05f5a72014-10-03 13:26:55 -0700427static void NestedSaveRestoreWithSolidPaintTestStep(SkCanvas* canvas, const TestData& d,
428 skiatest::Reporter*, CanvasTestStep*) {
reed@google.com3b3e8952012-08-16 20:53:31 +0000429 // This test step challenges the TestDeferredCanvasStateConsistency
430 // test cases because the opaque paint can trigger an optimization
431 // that discards previously recorded commands. The challenge is to maintain
432 // correct clip and matrix stack state.
433 canvas->resetMatrix();
434 canvas->rotate(SkIntToScalar(30));
435 canvas->save();
436 canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
437 canvas->save();
438 canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
439 SkPaint paint;
440 paint.setColor(0xFFFFFFFF);
441 canvas->drawPaint(paint);
442 canvas->restore();
443 canvas->restore();
444}
445TEST_STEP(NestedSaveRestoreWithSolidPaint, \
446 NestedSaveRestoreWithSolidPaintTestStep);
447
piotaixrf05f5a72014-10-03 13:26:55 -0700448static void NestedSaveRestoreWithFlushTestStep(SkCanvas* canvas, const TestData& d,
449 skiatest::Reporter*, CanvasTestStep*) {
reed@google.com3b3e8952012-08-16 20:53:31 +0000450 // This test step challenges the TestDeferredCanvasStateConsistency
451 // test case because the canvas flush on a deferred canvas will
452 // reset the recording session. The challenge is to maintain correct
453 // clip and matrix stack state on the playback canvas.
454 canvas->resetMatrix();
455 canvas->rotate(SkIntToScalar(30));
456 canvas->save();
457 canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
458 canvas->save();
459 canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
piotaixrf05f5a72014-10-03 13:26:55 -0700460 canvas->drawRect(d.fRect,d.fPaint);
reed@google.com3b3e8952012-08-16 20:53:31 +0000461 canvas->flush();
462 canvas->restore();
463 canvas->restore();
464}
piotaixrf05f5a72014-10-03 13:26:55 -0700465TEST_STEP(NestedSaveRestoreWithFlush, NestedSaveRestoreWithFlushTestStep);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000466
tomhudsoncb3bd182016-05-18 07:24:16 -0700467static void DescribeTopLayerTestStep(SkCanvas* canvas,
468 const TestData& d,
469 skiatest::Reporter* reporter,
470 CanvasTestStep* testStep) {
471 SkMatrix m;
472 SkIRect r;
473 // NOTE: adjustToTopLayer() does *not* reduce the clip size, even if the canvas
474 // is smaller than 10x10!
475
476 canvas->temporary_internal_describeTopLayer(&m, &r);
477 REPORTER_ASSERT_MESSAGE(reporter, m.isIdentity(), testStep->assertMessage());
478 REPORTER_ASSERT_MESSAGE(reporter, r == SkIRect::MakeXYWH(0, 0, 2, 2),
479 testStep->assertMessage());
480
481 // Putting a full-canvas layer on it should make no change to the results.
482 SkRect layerBounds = SkRect::MakeXYWH(0.f, 0.f, 10.f, 10.f);
483 canvas->saveLayer(layerBounds, nullptr);
484 canvas->temporary_internal_describeTopLayer(&m, &r);
485 REPORTER_ASSERT_MESSAGE(reporter, m.isIdentity(), testStep->assertMessage());
486 REPORTER_ASSERT_MESSAGE(reporter, r == SkIRect::MakeXYWH(0, 0, 2, 2),
487 testStep->assertMessage());
488 canvas->restore();
489
490 // Adding a translated layer translates the results.
491 // Default canvas is only 2x2, so can't offset our layer by very much at all;
492 // saveLayer() aborts if the bounds don't intersect.
493 layerBounds = SkRect::MakeXYWH(1.f, 1.f, 6.f, 6.f);
494 canvas->saveLayer(layerBounds, nullptr);
495 canvas->temporary_internal_describeTopLayer(&m, &r);
496 REPORTER_ASSERT_MESSAGE(reporter, m == SkMatrix::MakeTrans(-1.f, -1.f),
497 testStep->assertMessage());
498 REPORTER_ASSERT_MESSAGE(reporter, r == SkIRect::MakeXYWH(0, 0, 1, 1),
499 testStep->assertMessage());
500 canvas->restore();
501
502}
503TEST_STEP(DescribeTopLayer, DescribeTopLayerTestStep);
504
505
reed3aafe112016-08-18 12:45:34 -0700506static void TestPdfDevice(skiatest::Reporter* reporter, const TestData& d, CanvasTestStep* step) {
halcanary3d32d502015-03-01 06:55:20 -0800507 SkDynamicMemoryWStream outStream;
halcanary4b656662016-04-27 07:45:18 -0700508 sk_sp<SkDocument> doc(SkDocument::MakePDF(&outStream));
halcanary8ee06f22015-08-11 10:30:12 -0700509 REPORTER_ASSERT(reporter, doc);
halcanary2ccdb632015-08-11 13:35:12 -0700510 if (!doc) {
511 return;
512 }
halcanary3d32d502015-03-01 06:55:20 -0800513 SkCanvas* canvas = doc->beginPage(SkIntToScalar(d.fWidth),
514 SkIntToScalar(d.fHeight));
515 REPORTER_ASSERT(reporter, canvas);
reed3aafe112016-08-18 12:45:34 -0700516 step->setAssertMessageFormat(kPdfAssertMessageFormat);
517 step->draw(canvas, d, reporter);
halcanary3d32d502015-03-01 06:55:20 -0800518
519 REPORTER_ASSERT(reporter, doc->close());
edisonn@google.com77909122012-10-18 15:58:23 +0000520}
521
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000522/*
523 * This sub-test verifies that the test step passes when executed
524 * with SkCanvas and with classes derrived from SkCanvas. It also verifies
525 * that the all canvas derivatives report the same state as an SkCanvas
526 * after having executed the test step.
527 */
piotaixrf05f5a72014-10-03 13:26:55 -0700528static void TestOverrideStateConsistency(skiatest::Reporter* reporter, const TestData& d,
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000529 CanvasTestStep* testStep) {
530 SkBitmap referenceStore;
commit-bot@chromium.orgfa9e5fa2014-02-13 22:00:04 +0000531 createBitmap(&referenceStore, 0xFFFFFFFF);
reed2a8ca932014-06-26 22:12:09 -0700532 SkCanvas referenceCanvas(referenceStore);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000533 testStep->setAssertMessageFormat(kCanvasDrawAssertMessageFormat);
piotaixrf05f5a72014-10-03 13:26:55 -0700534 testStep->draw(&referenceCanvas, d, reporter);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000535
reed687fa1c2015-04-07 08:00:56 -0700536 test_clipstack(reporter);
reed@google.com7c202932011-12-14 18:48:05 +0000537}
reed@google.com37f3ae02011-11-28 16:06:04 +0000538
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000539static void test_newraster(skiatest::Reporter* reporter) {
540 SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10);
reed3054be12014-12-10 07:24:28 -0800541 const size_t minRowBytes = info.minRowBytes();
542 const size_t size = info.getSafeSize(minRowBytes);
scroggo565901d2015-12-10 10:44:13 -0800543 SkAutoTMalloc<SkPMColor> storage(size);
544 SkPMColor* baseAddr = storage.get();
reed3054be12014-12-10 07:24:28 -0800545 sk_bzero(baseAddr, size);
546
547 SkCanvas* canvas = SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes);
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000548 REPORTER_ASSERT(reporter, canvas);
549
reed6ceeebd2016-03-09 14:26:26 -0800550 SkPixmap pmap;
551 const SkPMColor* addr = canvas->peekPixels(&pmap) ? pmap.addr32() : nullptr;
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000552 REPORTER_ASSERT(reporter, addr);
reed6ceeebd2016-03-09 14:26:26 -0800553 REPORTER_ASSERT(reporter, info == pmap.info());
554 REPORTER_ASSERT(reporter, minRowBytes == pmap.rowBytes());
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000555 for (int y = 0; y < info.height(); ++y) {
556 for (int x = 0; x < info.width(); ++x) {
557 REPORTER_ASSERT(reporter, 0 == addr[x]);
558 }
reed6ceeebd2016-03-09 14:26:26 -0800559 addr = (const SkPMColor*)((const char*)addr + pmap.rowBytes());
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000560 }
halcanary385fe4d2015-08-26 13:07:48 -0700561 delete canvas;
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000562
563 // now try a deliberately bad info
reede5ea5002014-09-03 11:54:58 -0700564 info = info.makeWH(-1, info.height());
halcanary96fcdcc2015-08-27 07:41:13 -0700565 REPORTER_ASSERT(reporter, nullptr == SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes));
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000566
567 // too big
reede5ea5002014-09-03 11:54:58 -0700568 info = info.makeWH(1 << 30, 1 << 30);
halcanary96fcdcc2015-08-27 07:41:13 -0700569 REPORTER_ASSERT(reporter, nullptr == SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes));
skia.committer@gmail.com0e530752014-02-28 03:02:05 +0000570
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000571 // not a valid pixel type
reede5ea5002014-09-03 11:54:58 -0700572 info = SkImageInfo::Make(10, 10, kUnknown_SkColorType, info.alphaType());
halcanary96fcdcc2015-08-27 07:41:13 -0700573 REPORTER_ASSERT(reporter, nullptr == SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes));
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000574
575 // We should succeed with a zero-sized valid info
576 info = SkImageInfo::MakeN32Premul(0, 0);
reed3054be12014-12-10 07:24:28 -0800577 canvas = SkCanvas::NewRasterDirect(info, baseAddr, minRowBytes);
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000578 REPORTER_ASSERT(reporter, canvas);
halcanary385fe4d2015-08-26 13:07:48 -0700579 delete canvas;
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000580}
581
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000582DEF_TEST(Canvas, reporter) {
piotaixrf05f5a72014-10-03 13:26:55 -0700583 TestData d;
reed@google.com37f3ae02011-11-28 16:06:04 +0000584
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000585 for (int testStep = 0; testStep < testStepArray().count(); testStep++) {
piotaixrf05f5a72014-10-03 13:26:55 -0700586 TestOverrideStateConsistency(reporter, d, testStepArray()[testStep]);
edisonn@google.com77909122012-10-18 15:58:23 +0000587 if (testStepArray()[testStep]->enablePdfTesting()) {
piotaixrf05f5a72014-10-03 13:26:55 -0700588 TestPdfDevice(reporter, d, testStepArray()[testStep]);
edisonn@google.com77909122012-10-18 15:58:23 +0000589 }
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000590 }
junov@chromium.orgcd62ecf2012-08-02 17:43:25 +0000591
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000592 test_newraster(reporter);
reed@google.com37f3ae02011-11-28 16:06:04 +0000593}
reedf0090cb2014-11-26 08:55:51 -0800594
595DEF_TEST(Canvas_SaveState, reporter) {
596 SkCanvas canvas(10, 10);
597 REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
598
599 int n = canvas.save();
600 REPORTER_ASSERT(reporter, 1 == n);
601 REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
602
halcanary96fcdcc2015-08-27 07:41:13 -0700603 n = canvas.saveLayer(nullptr, nullptr);
reedf0090cb2014-11-26 08:55:51 -0800604 REPORTER_ASSERT(reporter, 2 == n);
605 REPORTER_ASSERT(reporter, 3 == canvas.getSaveCount());
halcanary9d524f22016-03-29 09:03:52 -0700606
reedf0090cb2014-11-26 08:55:51 -0800607 canvas.restore();
608 REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
609 canvas.restore();
610 REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
611}
reedc1b11f12015-03-13 08:48:26 -0700612
613DEF_TEST(Canvas_ClipEmptyPath, reporter) {
614 SkCanvas canvas(10, 10);
615 canvas.save();
616 SkPath path;
617 canvas.clipPath(path);
618 canvas.restore();
619 canvas.save();
620 path.moveTo(5, 5);
621 canvas.clipPath(path);
622 canvas.restore();
623 canvas.save();
624 path.moveTo(7, 7);
625 canvas.clipPath(path); // should not assert here
626 canvas.restore();
627}
fmalitaf433bb22015-08-17 08:05:13 -0700628
vjiaoblacke5de1302016-07-13 14:05:28 -0700629#define SHADOW_TEST_CANVAS_CONST 10
vjiaoblack95302da2016-07-21 10:25:54 -0700630#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -0700631class SkShadowTestCanvas : public SkPaintFilterCanvas {
632public:
633
634 SkShadowTestCanvas(int x, int y, skiatest::Reporter* reporter)
635 : INHERITED(x,y)
636 , fReporter(reporter) {}
637
638 bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const {
639 REPORTER_ASSERT(this->fReporter, this->getZ() == SHADOW_TEST_CANVAS_CONST);
640
641 return true;
642 }
643
644 void testUpdateDepth(skiatest::Reporter *reporter) {
645 // set some depths (with picture enabled), then check them as they get set
646
647 REPORTER_ASSERT(reporter, this->getZ() == 0);
648 this->translateZ(-10);
649 REPORTER_ASSERT(reporter, this->getZ() == -10);
650
651 this->save();
652 this->translateZ(20);
653 REPORTER_ASSERT(reporter, this->getZ() == 10);
654
655 this->restore();
656 REPORTER_ASSERT(reporter, this->getZ() == -10);
657
658 this->translateZ(13.14f);
659 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(this->getZ(), 3.14f));
660 }
661
662private:
663 skiatest::Reporter* fReporter;
664
665 typedef SkPaintFilterCanvas INHERITED;
666};
vjiaoblack95302da2016-07-21 10:25:54 -0700667#endif
vjiaoblacke5de1302016-07-13 14:05:28 -0700668
fmalitaf433bb22015-08-17 08:05:13 -0700669namespace {
670
671class MockFilterCanvas : public SkPaintFilterCanvas {
672public:
673 MockFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) { }
674
675protected:
fmalita32cdc322016-01-12 07:21:11 -0800676 bool onFilter(SkTCopyOnFirstWrite<SkPaint>*, Type) const override { return true; }
fmalitaf433bb22015-08-17 08:05:13 -0700677
678private:
679 typedef SkPaintFilterCanvas INHERITED;
680};
681
682} // anonymous namespace
683
684// SkPaintFilterCanvas should inherit the initial target canvas state.
685DEF_TEST(PaintFilterCanvas_ConsistentState, reporter) {
686 SkCanvas canvas(100, 100);
687 canvas.clipRect(SkRect::MakeXYWH(12.7f, 12.7f, 75, 75));
688 canvas.scale(0.5f, 0.75f);
689
690 SkRect clip1, clip2;
691
692 MockFilterCanvas filterCanvas(&canvas);
693 REPORTER_ASSERT(reporter, canvas.getTotalMatrix() == filterCanvas.getTotalMatrix());
694 REPORTER_ASSERT(reporter, canvas.getClipBounds(&clip1) == filterCanvas.getClipBounds(&clip2));
695 REPORTER_ASSERT(reporter, clip1 == clip2);
696
697 filterCanvas.clipRect(SkRect::MakeXYWH(30.5f, 30.7f, 100, 100));
698 filterCanvas.scale(0.75f, 0.5f);
699 REPORTER_ASSERT(reporter, canvas.getTotalMatrix() == filterCanvas.getTotalMatrix());
700 REPORTER_ASSERT(reporter, canvas.getClipBounds(&clip1) == filterCanvas.getClipBounds(&clip2));
701 REPORTER_ASSERT(reporter, clip1 == clip2);
vjiaoblacke5de1302016-07-13 14:05:28 -0700702
vjiaoblack95302da2016-07-21 10:25:54 -0700703#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -0700704 SkShadowTestCanvas* tCanvas = new SkShadowTestCanvas(100,100, reporter);
705 tCanvas->testUpdateDepth(reporter);
706 delete(tCanvas);
707
708 SkPictureRecorder recorder;
709 SkShadowTestCanvas *tSCanvas = new SkShadowTestCanvas(100, 100, reporter);
710 SkCanvas *tPCanvas = recorder.beginRecording(SkRect::MakeIWH(100, 100));
711
712 tPCanvas->translateZ(SHADOW_TEST_CANVAS_CONST);
713 sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
714 tSCanvas->drawPicture(pic);
715
716 delete(tSCanvas);
vjiaoblack95302da2016-07-21 10:25:54 -0700717#endif
fmalitaf433bb22015-08-17 08:05:13 -0700718}
reedbabc3de2016-07-08 08:43:27 -0700719
720///////////////////////////////////////////////////////////////////////////////////////////////////
721
722#include "SkDeferredCanvas.h"
723#include "SkDumpCanvas.h"
724
725DEF_TEST(DeferredCanvas, r) {
726 SkDebugfDumper dumper;
727 SkDumpCanvas dumpC(&dumper);
728
729 SkDeferredCanvas canvas(&dumpC);
730
731 SkPaint paint;
732// paint.setShader(SkShader::MakeColorShader(SK_ColorRED));
733
734 canvas.save();
735 canvas.clipRect(SkRect::MakeWH(55, 55));
736 canvas.translate(10, 20);
737 canvas.drawRect(SkRect::MakeWH(50, 50), paint);
738 canvas.restore();
739}
740