blob: 0d2ac295050bf45558ea8ab9b887f4cd6257f821 [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
Mike Reedc1f77742016-12-09 09:00:50 -0500176 void clipRect(const SkRect& r, SkClipOp op, bool aa) override {
reed@google.com90c07ea2012-04-13 13:50:27 +0000177 fTarget->clipRect(r, op, aa);
178 }
Mike Reedc1f77742016-12-09 09:00:50 -0500179 void clipRRect(const SkRRect& r, SkClipOp op, bool aa) override {
commit-bot@chromium.orge5b2af92014-02-16 13:25:24 +0000180 fTarget->clipRRect(r, op, aa);
181 }
Mike Reedc1f77742016-12-09 09:00:50 -0500182 void clipPath(const SkPath& p, SkClipOp 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) {
Mike Reed46784be2017-01-15 20:02:32 -0500191#ifdef SK_SUPPORT_LEGACY_CANVAS_GETCLIPSTACK
reed687fa1c2015-04-07 08:00:56 -0700192 // The clipstack is refcounted, and needs to be able to out-live the canvas if a client has
193 // ref'd it.
halcanary96fcdcc2015-08-27 07:41:13 -0700194 const SkClipStack* cs = nullptr;
reed687fa1c2015-04-07 08:00:56 -0700195 {
196 SkCanvas canvas(10, 10);
197 cs = SkRef(canvas.getClipStack());
198 }
199 REPORTER_ASSERT(reporter, cs->unique());
200 cs->unref();
Mike Reed46784be2017-01-15 20:02:32 -0500201#endif
reed687fa1c2015-04-07 08:00:56 -0700202}
203
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000204// Format strings that describe the test context. The %s token is where
205// the name of the test step is inserted. The context is required for
206// disambiguating the error in the case of failures that are reported in
207// functions that are called multiple times in different contexts (test
208// cases and test steps).
209static const char* const kDefaultAssertMessageFormat = "%s";
rmistry@google.comd6176b02012-08-23 18:14:13 +0000210static const char* const kCanvasDrawAssertMessageFormat =
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000211 "Drawing test step %s with SkCanvas";
edisonn@google.com77909122012-10-18 15:58:23 +0000212static const char* const kPdfAssertMessageFormat =
213 "PDF sanity check failed %s";
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000214
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000215class CanvasTestStep;
216static SkTDArray<CanvasTestStep*>& testStepArray() {
217 static SkTDArray<CanvasTestStep*> theTests;
218 return theTests;
219}
220
221class CanvasTestStep {
222public:
edisonn@google.com77909122012-10-18 15:58:23 +0000223 CanvasTestStep(bool fEnablePdfTesting = true) {
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000224 *testStepArray().append() = this;
225 fAssertMessageFormat = kDefaultAssertMessageFormat;
edisonn@google.com77909122012-10-18 15:58:23 +0000226 this->fEnablePdfTesting = fEnablePdfTesting;
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000227 }
djsollen@google.come63793a2012-03-21 15:39:03 +0000228 virtual ~CanvasTestStep() { }
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000229
piotaixrf05f5a72014-10-03 13:26:55 -0700230 virtual void draw(SkCanvas*, const TestData&, skiatest::Reporter*) = 0;
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000231 virtual const char* name() const = 0;
232
233 const char* assertMessage() {
234 fAssertMessage.printf(fAssertMessageFormat, name());
235 return fAssertMessage.c_str();
236 }
237
238 void setAssertMessageFormat(const char* format) {
239 fAssertMessageFormat = format;
240 }
241
edisonn@google.com77909122012-10-18 15:58:23 +0000242 bool enablePdfTesting() { return fEnablePdfTesting; }
243
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000244private:
245 SkString fAssertMessage;
246 const char* fAssertMessageFormat;
edisonn@google.com77909122012-10-18 15:58:23 +0000247 bool fEnablePdfTesting;
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000248};
249
250///////////////////////////////////////////////////////////////////////////////
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000251// Macros for defining test steps
252
253#define TEST_STEP(NAME, FUNCTION) \
254class NAME##_TestStep : public CanvasTestStep{ \
255public: \
piotaixrf05f5a72014-10-03 13:26:55 -0700256 virtual void draw(SkCanvas* canvas, const TestData& d, \
257 skiatest::Reporter* reporter) { \
258 FUNCTION (canvas, d, reporter, this); \
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000259 } \
260 virtual const char* name() const {return #NAME ;} \
261}; \
262static NAME##_TestStep NAME##_TestStepInstance;
263
piotaixrf05f5a72014-10-03 13:26:55 -0700264#define TEST_STEP_NO_PDF(NAME, FUNCTION) \
edisonn@google.com77909122012-10-18 15:58:23 +0000265class NAME##_TestStep : public CanvasTestStep{ \
266public: \
267 NAME##_TestStep() : CanvasTestStep(false) {} \
piotaixrf05f5a72014-10-03 13:26:55 -0700268 virtual void draw(SkCanvas* canvas, const TestData& d, \
269 skiatest::Reporter* reporter) { \
270 FUNCTION (canvas, d, reporter, this); \
edisonn@google.com77909122012-10-18 15:58:23 +0000271 } \
272 virtual const char* name() const {return #NAME ;} \
273}; \
274static NAME##_TestStep NAME##_TestStepInstance;
275
piotaixrf05f5a72014-10-03 13:26:55 -0700276#define SIMPLE_TEST_STEP(NAME, CALL) \
277static void NAME##TestStep(SkCanvas* canvas, const TestData& d, \
278 skiatest::Reporter*, CanvasTestStep*) { \
279 canvas-> CALL ; \
280} \
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000281TEST_STEP(NAME, NAME##TestStep )
282
283#define SIMPLE_TEST_STEP_WITH_ASSERT(NAME, CALL) \
piotaixrf05f5a72014-10-03 13:26:55 -0700284static void NAME##TestStep(SkCanvas* canvas, const TestData& d, \
285 skiatest::Reporter*, CanvasTestStep* testStep) { \
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000286 REPORTER_ASSERT_MESSAGE(reporter, canvas-> CALL , \
287 testStep->assertMessage()); \
288} \
289TEST_STEP(NAME, NAME##TestStep )
290
291
292///////////////////////////////////////////////////////////////////////////////
rmistry@google.comd6176b02012-08-23 18:14:13 +0000293// Basic test steps for most virtual methods in SkCanvas that draw or affect
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000294// the state of the canvas.
295
commit-bot@chromium.org92362382014-03-18 12:51:48 +0000296SIMPLE_TEST_STEP(Translate, translate(SkIntToScalar(1), SkIntToScalar(2)));
297SIMPLE_TEST_STEP(Scale, scale(SkIntToScalar(1), SkIntToScalar(2)));
298SIMPLE_TEST_STEP(Rotate, rotate(SkIntToScalar(1)));
299SIMPLE_TEST_STEP(Skew, skew(SkIntToScalar(1), SkIntToScalar(2)));
piotaixrf05f5a72014-10-03 13:26:55 -0700300SIMPLE_TEST_STEP(Concat, concat(d.fMatrix));
301SIMPLE_TEST_STEP(SetMatrix, setMatrix(d.fMatrix));
302SIMPLE_TEST_STEP(ClipRect, clipRect(d.fRect));
303SIMPLE_TEST_STEP(ClipPath, clipPath(d.fPath));
Mike Reedc1f77742016-12-09 09:00:50 -0500304SIMPLE_TEST_STEP(ClipRegion, clipRegion(d.fRegion, kReplace_SkClipOp));
piotaixrf05f5a72014-10-03 13:26:55 -0700305SIMPLE_TEST_STEP(Clear, clear(d.fColor));
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000306
307///////////////////////////////////////////////////////////////////////////////
308// Complex test steps
309
piotaixrf05f5a72014-10-03 13:26:55 -0700310static void SaveMatrixClipStep(SkCanvas* canvas, const TestData& d,
311 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000312 int saveCount = canvas->getSaveCount();
Florin Malita5f6102d2014-06-30 10:13:28 -0400313 canvas->save();
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000314 canvas->translate(SkIntToScalar(1), SkIntToScalar(2));
piotaixrf05f5a72014-10-03 13:26:55 -0700315 canvas->clipRegion(d.fRegion);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000316 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000317 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000318 testStep->assertMessage());
rmistry@google.comd6176b02012-08-23 18:14:13 +0000319 REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalMatrix().isIdentity(),
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000320 testStep->assertMessage());
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +0000321// REPORTER_ASSERT_MESSAGE(reporter, canvas->getTotalClip() != kTestRegion, testStep->assertMessage());
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000322}
323TEST_STEP(SaveMatrixClip, SaveMatrixClipStep);
324
piotaixrf05f5a72014-10-03 13:26:55 -0700325static void SaveLayerStep(SkCanvas* canvas, const TestData& d,
326 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000327 int saveCount = canvas->getSaveCount();
halcanary96fcdcc2015-08-27 07:41:13 -0700328 canvas->saveLayer(nullptr, nullptr);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000329 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000330 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000331 testStep->assertMessage());
332}
333TEST_STEP(SaveLayer, SaveLayerStep);
334
piotaixrf05f5a72014-10-03 13:26:55 -0700335static void BoundedSaveLayerStep(SkCanvas* canvas, const TestData& d,
336 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000337 int saveCount = canvas->getSaveCount();
halcanary96fcdcc2015-08-27 07:41:13 -0700338 canvas->saveLayer(&d.fRect, nullptr);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000339 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000340 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000341 testStep->assertMessage());
342}
343TEST_STEP(BoundedSaveLayer, BoundedSaveLayerStep);
344
piotaixrf05f5a72014-10-03 13:26:55 -0700345static void PaintSaveLayerStep(SkCanvas* canvas, const TestData& d,
346 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000347 int saveCount = canvas->getSaveCount();
halcanary96fcdcc2015-08-27 07:41:13 -0700348 canvas->saveLayer(nullptr, &d.fPaint);
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000349 canvas->restore();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000350 REPORTER_ASSERT_MESSAGE(reporter, canvas->getSaveCount() == saveCount,
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000351 testStep->assertMessage());
352}
353TEST_STEP(PaintSaveLayer, PaintSaveLayerStep);
354
piotaixrf05f5a72014-10-03 13:26:55 -0700355static void TwoClipOpsStep(SkCanvas* canvas, const TestData& d,
356 skiatest::Reporter*, CanvasTestStep*) {
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000357 // This test exercises a functionality in SkPicture that leads to the
rmistry@google.comd6176b02012-08-23 18:14:13 +0000358 // recording of restore offset placeholders. This test will trigger an
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000359 // assertion at playback time if the placeholders are not properly
360 // filled when the recording ends.
piotaixrf05f5a72014-10-03 13:26:55 -0700361 canvas->clipRect(d.fRect);
362 canvas->clipRegion(d.fRegion);
junov@chromium.orga6c9e0e2012-07-12 17:47:34 +0000363}
364TEST_STEP(TwoClipOps, TwoClipOpsStep);
365
epoger@google.com94fa43c2012-04-11 17:51:01 +0000366// exercise fix for http://code.google.com/p/skia/issues/detail?id=560
367// ('SkPathStroker::lineTo() fails for line with length SK_ScalarNearlyZero')
piotaixrf05f5a72014-10-03 13:26:55 -0700368static void DrawNearlyZeroLengthPathTestStep(SkCanvas* canvas, const TestData& d,
369 skiatest::Reporter*, CanvasTestStep*) {
epoger@google.com94fa43c2012-04-11 17:51:01 +0000370 SkPaint paint;
371 paint.setStrokeWidth(SkIntToScalar(1));
372 paint.setStyle(SkPaint::kStroke_Style);
373
piotaixrf05f5a72014-10-03 13:26:55 -0700374 canvas->drawPath(d.fNearlyZeroLengthPath, paint);
epoger@google.com94fa43c2012-04-11 17:51:01 +0000375}
376TEST_STEP(DrawNearlyZeroLengthPath, DrawNearlyZeroLengthPathTestStep);
377
piotaixrf05f5a72014-10-03 13:26:55 -0700378static void DrawVerticesShaderTestStep(SkCanvas* canvas, const TestData& d,
379 skiatest::Reporter*, CanvasTestStep*) {
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000380 SkPoint pts[4];
381 pts[0].set(0, 0);
piotaixrf05f5a72014-10-03 13:26:55 -0700382 pts[1].set(SkIntToScalar(d.fWidth), 0);
383 pts[2].set(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight));
384 pts[3].set(0, SkIntToScalar(d.fHeight));
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000385 SkPaint paint;
reed1a9b9642016-03-13 14:13:58 -0700386 paint.setShader(SkShader::MakeBitmapShader(d.fBitmap, SkShader::kClamp_TileMode,
387 SkShader::kClamp_TileMode));
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000388 canvas->drawVertices(SkCanvas::kTriangleFan_VertexMode, 4, pts, pts,
Mike Reed7d954ad2016-10-28 15:42:34 -0400389 nullptr, SkBlendMode::kModulate, nullptr, 0, paint);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000390}
edisonn@google.com77909122012-10-18 15:58:23 +0000391// NYI: issue 240.
392TEST_STEP_NO_PDF(DrawVerticesShader, DrawVerticesShaderTestStep);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000393
piotaixrf05f5a72014-10-03 13:26:55 -0700394static void DrawPictureTestStep(SkCanvas* canvas, const TestData& d,
395 skiatest::Reporter*, CanvasTestStep*) {
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000396 SkPictureRecorder recorder;
piotaixrf05f5a72014-10-03 13:26:55 -0700397 SkCanvas* testCanvas = recorder.beginRecording(SkIntToScalar(d.fWidth), SkIntToScalar(d.fHeight),
halcanary96fcdcc2015-08-27 07:41:13 -0700398 nullptr, 0);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000399 testCanvas->scale(SkIntToScalar(2), SkIntToScalar(1));
piotaixrf05f5a72014-10-03 13:26:55 -0700400 testCanvas->clipRect(d.fRect);
401 testCanvas->drawRect(d.fRect, d.fPaint);
robertphillips@google.com84b18c72014-04-13 19:09:42 +0000402
reedca2622b2016-03-18 07:25:55 -0700403 canvas->drawPicture(recorder.finishRecordingAsPicture());
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000404}
405TEST_STEP(DrawPicture, DrawPictureTestStep);
406
piotaixrf05f5a72014-10-03 13:26:55 -0700407static void SaveRestoreTestStep(SkCanvas* canvas, const TestData& d,
408 skiatest::Reporter* reporter, CanvasTestStep* testStep) {
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000409 int baseSaveCount = canvas->getSaveCount();
tomhudson@google.com8afae612012-08-14 15:03:35 +0000410 int n = canvas->save();
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000411 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount == n, testStep->assertMessage());
412 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000413 testStep->assertMessage());
414 canvas->save();
415 canvas->save();
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000416 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 3 == canvas->getSaveCount(),
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000417 testStep->assertMessage());
junov@chromium.org4e6dfa52012-07-16 14:04:59 +0000418 canvas->restoreToCount(baseSaveCount + 1);
419 REPORTER_ASSERT_MESSAGE(reporter, baseSaveCount + 1 == canvas->getSaveCount(),
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000420 testStep->assertMessage());
421
422 // should this pin to 1, or be a no-op, or crash?
423 canvas->restoreToCount(0);
424 REPORTER_ASSERT_MESSAGE(reporter, 1 == canvas->getSaveCount(),
425 testStep->assertMessage());
426}
427TEST_STEP(SaveRestore, SaveRestoreTestStep);
428
piotaixrf05f5a72014-10-03 13:26:55 -0700429static void NestedSaveRestoreWithSolidPaintTestStep(SkCanvas* canvas, const TestData& d,
430 skiatest::Reporter*, CanvasTestStep*) {
reed@google.com3b3e8952012-08-16 20:53:31 +0000431 // This test step challenges the TestDeferredCanvasStateConsistency
432 // test cases because the opaque paint can trigger an optimization
433 // that discards previously recorded commands. The challenge is to maintain
434 // correct clip and matrix stack state.
435 canvas->resetMatrix();
436 canvas->rotate(SkIntToScalar(30));
437 canvas->save();
438 canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
439 canvas->save();
440 canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
441 SkPaint paint;
442 paint.setColor(0xFFFFFFFF);
443 canvas->drawPaint(paint);
444 canvas->restore();
445 canvas->restore();
446}
447TEST_STEP(NestedSaveRestoreWithSolidPaint, \
448 NestedSaveRestoreWithSolidPaintTestStep);
449
piotaixrf05f5a72014-10-03 13:26:55 -0700450static void NestedSaveRestoreWithFlushTestStep(SkCanvas* canvas, const TestData& d,
451 skiatest::Reporter*, CanvasTestStep*) {
reed@google.com3b3e8952012-08-16 20:53:31 +0000452 // This test step challenges the TestDeferredCanvasStateConsistency
453 // test case because the canvas flush on a deferred canvas will
454 // reset the recording session. The challenge is to maintain correct
455 // clip and matrix stack state on the playback canvas.
456 canvas->resetMatrix();
457 canvas->rotate(SkIntToScalar(30));
458 canvas->save();
459 canvas->translate(SkIntToScalar(2), SkIntToScalar(1));
460 canvas->save();
461 canvas->scale(SkIntToScalar(3), SkIntToScalar(3));
piotaixrf05f5a72014-10-03 13:26:55 -0700462 canvas->drawRect(d.fRect,d.fPaint);
reed@google.com3b3e8952012-08-16 20:53:31 +0000463 canvas->flush();
464 canvas->restore();
465 canvas->restore();
466}
piotaixrf05f5a72014-10-03 13:26:55 -0700467TEST_STEP(NestedSaveRestoreWithFlush, NestedSaveRestoreWithFlushTestStep);
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000468
tomhudsoncb3bd182016-05-18 07:24:16 -0700469static void DescribeTopLayerTestStep(SkCanvas* canvas,
470 const TestData& d,
471 skiatest::Reporter* reporter,
472 CanvasTestStep* testStep) {
473 SkMatrix m;
474 SkIRect r;
475 // NOTE: adjustToTopLayer() does *not* reduce the clip size, even if the canvas
476 // is smaller than 10x10!
477
478 canvas->temporary_internal_describeTopLayer(&m, &r);
479 REPORTER_ASSERT_MESSAGE(reporter, m.isIdentity(), testStep->assertMessage());
480 REPORTER_ASSERT_MESSAGE(reporter, r == SkIRect::MakeXYWH(0, 0, 2, 2),
481 testStep->assertMessage());
482
483 // Putting a full-canvas layer on it should make no change to the results.
484 SkRect layerBounds = SkRect::MakeXYWH(0.f, 0.f, 10.f, 10.f);
485 canvas->saveLayer(layerBounds, nullptr);
486 canvas->temporary_internal_describeTopLayer(&m, &r);
487 REPORTER_ASSERT_MESSAGE(reporter, m.isIdentity(), testStep->assertMessage());
488 REPORTER_ASSERT_MESSAGE(reporter, r == SkIRect::MakeXYWH(0, 0, 2, 2),
489 testStep->assertMessage());
490 canvas->restore();
491
492 // Adding a translated layer translates the results.
493 // Default canvas is only 2x2, so can't offset our layer by very much at all;
494 // saveLayer() aborts if the bounds don't intersect.
495 layerBounds = SkRect::MakeXYWH(1.f, 1.f, 6.f, 6.f);
496 canvas->saveLayer(layerBounds, nullptr);
497 canvas->temporary_internal_describeTopLayer(&m, &r);
498 REPORTER_ASSERT_MESSAGE(reporter, m == SkMatrix::MakeTrans(-1.f, -1.f),
499 testStep->assertMessage());
500 REPORTER_ASSERT_MESSAGE(reporter, r == SkIRect::MakeXYWH(0, 0, 1, 1),
501 testStep->assertMessage());
502 canvas->restore();
503
504}
505TEST_STEP(DescribeTopLayer, DescribeTopLayerTestStep);
506
507
reed3aafe112016-08-18 12:45:34 -0700508static void TestPdfDevice(skiatest::Reporter* reporter, const TestData& d, CanvasTestStep* step) {
halcanary3d32d502015-03-01 06:55:20 -0800509 SkDynamicMemoryWStream outStream;
halcanary4b656662016-04-27 07:45:18 -0700510 sk_sp<SkDocument> doc(SkDocument::MakePDF(&outStream));
halcanary8ee06f22015-08-11 10:30:12 -0700511 REPORTER_ASSERT(reporter, doc);
halcanary2ccdb632015-08-11 13:35:12 -0700512 if (!doc) {
513 return;
514 }
halcanary3d32d502015-03-01 06:55:20 -0800515 SkCanvas* canvas = doc->beginPage(SkIntToScalar(d.fWidth),
516 SkIntToScalar(d.fHeight));
517 REPORTER_ASSERT(reporter, canvas);
reed3aafe112016-08-18 12:45:34 -0700518 step->setAssertMessageFormat(kPdfAssertMessageFormat);
519 step->draw(canvas, d, reporter);
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
Mike Reed5df49342016-11-12 08:06:55 -0600547 std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(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 }
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000561
562 // now try a deliberately bad info
reede5ea5002014-09-03 11:54:58 -0700563 info = info.makeWH(-1, info.height());
Mike Reed5df49342016-11-12 08:06:55 -0600564 REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes));
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000565
566 // too big
reede5ea5002014-09-03 11:54:58 -0700567 info = info.makeWH(1 << 30, 1 << 30);
Mike Reed5df49342016-11-12 08:06:55 -0600568 REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes));
skia.committer@gmail.com0e530752014-02-28 03:02:05 +0000569
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000570 // not a valid pixel type
reede5ea5002014-09-03 11:54:58 -0700571 info = SkImageInfo::Make(10, 10, kUnknown_SkColorType, info.alphaType());
Mike Reed5df49342016-11-12 08:06:55 -0600572 REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes));
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000573
574 // We should succeed with a zero-sized valid info
575 info = SkImageInfo::MakeN32Premul(0, 0);
Mike Reed5df49342016-11-12 08:06:55 -0600576 canvas = SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes);
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000577 REPORTER_ASSERT(reporter, canvas);
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000578}
579
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000580DEF_TEST(Canvas, reporter) {
piotaixrf05f5a72014-10-03 13:26:55 -0700581 TestData d;
reed@google.com37f3ae02011-11-28 16:06:04 +0000582
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000583 for (int testStep = 0; testStep < testStepArray().count(); testStep++) {
piotaixrf05f5a72014-10-03 13:26:55 -0700584 TestOverrideStateConsistency(reporter, d, testStepArray()[testStep]);
edisonn@google.com77909122012-10-18 15:58:23 +0000585 if (testStepArray()[testStep]->enablePdfTesting()) {
piotaixrf05f5a72014-10-03 13:26:55 -0700586 TestPdfDevice(reporter, d, testStepArray()[testStep]);
edisonn@google.com77909122012-10-18 15:58:23 +0000587 }
junov@chromium.org1cc8f6f2012-02-22 21:00:42 +0000588 }
junov@chromium.orgcd62ecf2012-08-02 17:43:25 +0000589
commit-bot@chromium.org3107b6a2014-02-27 20:32:51 +0000590 test_newraster(reporter);
reed@google.com37f3ae02011-11-28 16:06:04 +0000591}
reedf0090cb2014-11-26 08:55:51 -0800592
593DEF_TEST(Canvas_SaveState, reporter) {
594 SkCanvas canvas(10, 10);
595 REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
596
597 int n = canvas.save();
598 REPORTER_ASSERT(reporter, 1 == n);
599 REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
600
halcanary96fcdcc2015-08-27 07:41:13 -0700601 n = canvas.saveLayer(nullptr, nullptr);
reedf0090cb2014-11-26 08:55:51 -0800602 REPORTER_ASSERT(reporter, 2 == n);
603 REPORTER_ASSERT(reporter, 3 == canvas.getSaveCount());
halcanary9d524f22016-03-29 09:03:52 -0700604
reedf0090cb2014-11-26 08:55:51 -0800605 canvas.restore();
606 REPORTER_ASSERT(reporter, 2 == canvas.getSaveCount());
607 canvas.restore();
608 REPORTER_ASSERT(reporter, 1 == canvas.getSaveCount());
609}
reedc1b11f12015-03-13 08:48:26 -0700610
611DEF_TEST(Canvas_ClipEmptyPath, reporter) {
612 SkCanvas canvas(10, 10);
613 canvas.save();
614 SkPath path;
615 canvas.clipPath(path);
616 canvas.restore();
617 canvas.save();
618 path.moveTo(5, 5);
619 canvas.clipPath(path);
620 canvas.restore();
621 canvas.save();
622 path.moveTo(7, 7);
623 canvas.clipPath(path); // should not assert here
624 canvas.restore();
625}
fmalitaf433bb22015-08-17 08:05:13 -0700626
vjiaoblacke5de1302016-07-13 14:05:28 -0700627#define SHADOW_TEST_CANVAS_CONST 10
vjiaoblack95302da2016-07-21 10:25:54 -0700628#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -0700629class SkShadowTestCanvas : public SkPaintFilterCanvas {
630public:
631
632 SkShadowTestCanvas(int x, int y, skiatest::Reporter* reporter)
633 : INHERITED(x,y)
634 , fReporter(reporter) {}
635
636 bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const {
637 REPORTER_ASSERT(this->fReporter, this->getZ() == SHADOW_TEST_CANVAS_CONST);
638
639 return true;
640 }
641
642 void testUpdateDepth(skiatest::Reporter *reporter) {
643 // set some depths (with picture enabled), then check them as they get set
644
645 REPORTER_ASSERT(reporter, this->getZ() == 0);
646 this->translateZ(-10);
647 REPORTER_ASSERT(reporter, this->getZ() == -10);
648
649 this->save();
650 this->translateZ(20);
651 REPORTER_ASSERT(reporter, this->getZ() == 10);
652
653 this->restore();
654 REPORTER_ASSERT(reporter, this->getZ() == -10);
655
656 this->translateZ(13.14f);
657 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(this->getZ(), 3.14f));
658 }
659
660private:
661 skiatest::Reporter* fReporter;
662
663 typedef SkPaintFilterCanvas INHERITED;
664};
vjiaoblack95302da2016-07-21 10:25:54 -0700665#endif
vjiaoblacke5de1302016-07-13 14:05:28 -0700666
fmalitaf433bb22015-08-17 08:05:13 -0700667namespace {
668
669class MockFilterCanvas : public SkPaintFilterCanvas {
670public:
671 MockFilterCanvas(SkCanvas* canvas) : INHERITED(canvas) { }
672
673protected:
fmalita32cdc322016-01-12 07:21:11 -0800674 bool onFilter(SkTCopyOnFirstWrite<SkPaint>*, Type) const override { return true; }
fmalitaf433bb22015-08-17 08:05:13 -0700675
676private:
677 typedef SkPaintFilterCanvas INHERITED;
678};
679
680} // anonymous namespace
681
682// SkPaintFilterCanvas should inherit the initial target canvas state.
683DEF_TEST(PaintFilterCanvas_ConsistentState, reporter) {
684 SkCanvas canvas(100, 100);
685 canvas.clipRect(SkRect::MakeXYWH(12.7f, 12.7f, 75, 75));
686 canvas.scale(0.5f, 0.75f);
687
688 SkRect clip1, clip2;
689
690 MockFilterCanvas filterCanvas(&canvas);
691 REPORTER_ASSERT(reporter, canvas.getTotalMatrix() == filterCanvas.getTotalMatrix());
692 REPORTER_ASSERT(reporter, canvas.getClipBounds(&clip1) == filterCanvas.getClipBounds(&clip2));
693 REPORTER_ASSERT(reporter, clip1 == clip2);
694
695 filterCanvas.clipRect(SkRect::MakeXYWH(30.5f, 30.7f, 100, 100));
696 filterCanvas.scale(0.75f, 0.5f);
697 REPORTER_ASSERT(reporter, canvas.getTotalMatrix() == filterCanvas.getTotalMatrix());
698 REPORTER_ASSERT(reporter, canvas.getClipBounds(&clip1) == filterCanvas.getClipBounds(&clip2));
Mike Klein1a427912016-11-29 13:46:06 -0500699 REPORTER_ASSERT(reporter, clip2.contains(clip1));
vjiaoblacke5de1302016-07-13 14:05:28 -0700700
vjiaoblack95302da2016-07-21 10:25:54 -0700701#ifdef SK_EXPERIMENTAL_SHADOWING
vjiaoblacke5de1302016-07-13 14:05:28 -0700702 SkShadowTestCanvas* tCanvas = new SkShadowTestCanvas(100,100, reporter);
703 tCanvas->testUpdateDepth(reporter);
704 delete(tCanvas);
705
706 SkPictureRecorder recorder;
707 SkShadowTestCanvas *tSCanvas = new SkShadowTestCanvas(100, 100, reporter);
708 SkCanvas *tPCanvas = recorder.beginRecording(SkRect::MakeIWH(100, 100));
709
710 tPCanvas->translateZ(SHADOW_TEST_CANVAS_CONST);
711 sk_sp<SkPicture> pic = recorder.finishRecordingAsPicture();
712 tSCanvas->drawPicture(pic);
713
714 delete(tSCanvas);
vjiaoblack95302da2016-07-21 10:25:54 -0700715#endif
fmalitaf433bb22015-08-17 08:05:13 -0700716}
reedbabc3de2016-07-08 08:43:27 -0700717
718///////////////////////////////////////////////////////////////////////////////////////////////////
719
720#include "SkDeferredCanvas.h"
721#include "SkDumpCanvas.h"
722
723DEF_TEST(DeferredCanvas, r) {
724 SkDebugfDumper dumper;
725 SkDumpCanvas dumpC(&dumper);
726
727 SkDeferredCanvas canvas(&dumpC);
728
729 SkPaint paint;
730// paint.setShader(SkShader::MakeColorShader(SK_ColorRED));
731
732 canvas.save();
733 canvas.clipRect(SkRect::MakeWH(55, 55));
734 canvas.translate(10, 20);
735 canvas.drawRect(SkRect::MakeWH(50, 50), paint);
736 canvas.restore();
737}
738
Mike Reed584ca892016-11-15 11:52:55 -0500739///////////////////////////////////////////////////////////////////////////////////////////////////
740
741#include "SkCanvasStack.h"
742#include "SkNWayCanvas.h"
743
744// Subclass that takes a bool*, which it updates in its construct (true) and destructor (false)
745// to allow the caller to know how long the object is alive.
746class LifeLineCanvas : public SkCanvas {
747 bool* fLifeLine;
748public:
749 LifeLineCanvas(int w, int h, bool* lifeline) : SkCanvas(w, h), fLifeLine(lifeline) {
750 *fLifeLine = true;
751 }
752 ~LifeLineCanvas() {
753 *fLifeLine = false;
754 }
755};
756
757// Check that NWayCanvas does NOT try to manage the lifetime of its sub-canvases
758DEF_TEST(NWayCanvas, r) {
759 const int w = 10;
760 const int h = 10;
761 bool life[2];
762 {
763 LifeLineCanvas c0(w, h, &life[0]);
764 REPORTER_ASSERT(r, life[0]);
765 }
766 REPORTER_ASSERT(r, !life[0]);
767
768
769 std::unique_ptr<SkCanvas> c0 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[0]));
770 std::unique_ptr<SkCanvas> c1 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[1]));
771 REPORTER_ASSERT(r, life[0]);
772 REPORTER_ASSERT(r, life[1]);
773
774 {
775 SkNWayCanvas nway(w, h);
776 nway.addCanvas(c0.get());
777 nway.addCanvas(c1.get());
778 REPORTER_ASSERT(r, life[0]);
779 REPORTER_ASSERT(r, life[1]);
780 }
781 // Now assert that the death of the nway has NOT also killed the sub-canvases
782 REPORTER_ASSERT(r, life[0]);
783 REPORTER_ASSERT(r, life[1]);
784}
785
786// Check that CanvasStack DOES manage the lifetime of its sub-canvases
787DEF_TEST(CanvasStack, r) {
788 const int w = 10;
789 const int h = 10;
790 bool life[2];
791 std::unique_ptr<SkCanvas> c0 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[0]));
792 std::unique_ptr<SkCanvas> c1 = std::unique_ptr<SkCanvas>(new LifeLineCanvas(w, h, &life[1]));
793 REPORTER_ASSERT(r, life[0]);
794 REPORTER_ASSERT(r, life[1]);
795
796 {
797 SkCanvasStack stack(w, h);
798 stack.pushCanvas(std::move(c0), {0,0});
799 stack.pushCanvas(std::move(c1), {0,0});
800 REPORTER_ASSERT(r, life[0]);
801 REPORTER_ASSERT(r, life[1]);
802 }
803 // Now assert that the death of the canvasstack has also killed the sub-canvases
804 REPORTER_ASSERT(r, !life[0]);
805 REPORTER_ASSERT(r, !life[1]);
806}