blob: 881b3ae06ec023fe4587c0ccc0363c1fd93b07f3 [file] [log] [blame]
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2011 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.
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +00006 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040013#include "include/core/SkPathEffect.h"
Kevin Lubick177a7122022-12-12 10:25:15 -050014#include "include/core/SkPathUtils.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040015#include "include/core/SkPoint.h"
16#include "include/core/SkRect.h"
17#include "include/core/SkScalar.h"
18#include "include/core/SkSize.h"
19#include "include/core/SkString.h"
20#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/effects/SkDashPathEffect.h"
Kevin Lubickdc6cc022023-01-13 11:24:27 -050022#include "include/private/base/SkFloatBits.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/utils/SkParsePath.h"
Kevin Lubick0d4d1142023-02-13 09:13:10 -050024#include "src/base/SkRandom.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "tools/ToolUtils.h"
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000026
Ben Wagner7fde8e12019-05-01 17:28:53 -040027#include <string.h>
28
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000029#define W 400
30#define H 400
31#define N 50
32
mtkleindbfd7ab2016-09-01 11:24:54 -070033constexpr SkScalar SW = SkIntToScalar(W);
34constexpr SkScalar SH = SkIntToScalar(H);
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000035
scroggof9d61012014-12-15 12:54:51 -080036static void rnd_rect(SkRect* r, SkPaint* paint, SkRandom& rand) {
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000037 SkScalar x = rand.nextUScalar1() * W;
38 SkScalar y = rand.nextUScalar1() * H;
39 SkScalar w = rand.nextUScalar1() * (W >> 2);
40 SkScalar h = rand.nextUScalar1() * (H >> 2);
epoger@google.com17b78942011-08-26 14:40:38 +000041 SkScalar hoffset = rand.nextSScalar1();
42 SkScalar woffset = rand.nextSScalar1();
rmistry@google.comae933ce2012-08-23 18:19:56 +000043
Mike Reed92b33352019-08-24 19:39:13 -040044 r->setXYWH(x, y, w, h);
epoger@google.com17b78942011-08-26 14:40:38 +000045 r->offset(-w/2 + woffset, -h/2 + hoffset);
rmistry@google.comae933ce2012-08-23 18:19:56 +000046
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000047 paint->setColor(rand.nextU());
Mike Reed9407e242019-02-15 16:13:57 -050048 paint->setAlphaf(1.0f);
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000049}
50
rmistry@google.comae933ce2012-08-23 18:19:56 +000051
reed@google.com4384fab2012-06-05 16:14:23 +000052class StrokesGM : public skiagm::GM {
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000053public:
54 StrokesGM() {}
rmistry@google.comae933ce2012-08-23 18:19:56 +000055
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000056protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +000057 SkString getName() const override { return SkString("strokes_round"); }
rmistry@google.comae933ce2012-08-23 18:19:56 +000058
Leandro Lovisolo8f023882023-08-15 21:13:52 +000059 SkISize getISize() override { return SkISize::Make(W, H * 2); }
rmistry@google.comae933ce2012-08-23 18:19:56 +000060
mtklein36352bf2015-03-25 18:17:31 -070061 void onDraw(SkCanvas* canvas) override {
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000062 SkPaint paint;
63 paint.setStyle(SkPaint::kStroke_Style);
64 paint.setStrokeWidth(SkIntToScalar(9)/2);
rmistry@google.comae933ce2012-08-23 18:19:56 +000065
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000066 for (int y = 0; y < 2; y++) {
67 paint.setAntiAlias(!!y);
68 SkAutoCanvasRestore acr(canvas, true);
69 canvas->translate(0, SH * y);
70 canvas->clipRect(SkRect::MakeLTRB(
71 SkIntToScalar(2), SkIntToScalar(2)
72 , SW - SkIntToScalar(2), SH - SkIntToScalar(2)
73 ));
rmistry@google.comae933ce2012-08-23 18:19:56 +000074
scroggof9d61012014-12-15 12:54:51 -080075 SkRandom rand;
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000076 for (int i = 0; i < N; i++) {
77 SkRect r;
78 rnd_rect(&r, &paint, rand);
79 canvas->drawOval(r, paint);
80 rnd_rect(&r, &paint, rand);
81 canvas->drawRoundRect(r, r.width()/4, r.height()/4, paint);
82 rnd_rect(&r, &paint, rand);
83 }
84 }
85 }
rmistry@google.comae933ce2012-08-23 18:19:56 +000086
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000087private:
John Stiles7571f9e2020-09-02 22:42:33 -040088 using INHERITED = skiagm::GM;
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +000089};
90
caryclark5cb00a92015-08-26 09:04:55 -070091/* See
92 https://code.google.com/p/chromium/issues/detail?id=422974 and
93 http://jsfiddle.net/1xnku3sg/2/
94 */
95class ZeroLenStrokesGM : public skiagm::GM {
96 SkPath fMoveHfPath, fMoveZfPath, fDashedfPath, fRefPath[4];
caryclark6651a322015-09-09 13:20:49 -070097 SkPath fCubicPath, fQuadPath, fLinePath;
caryclark5cb00a92015-08-26 09:04:55 -070098protected:
99 void onOnceBeforeDraw() override {
100
101 SkAssertResult(SkParsePath::FromSVGString("M0,0h0M10,0h0M20,0h0", &fMoveHfPath));
102 SkAssertResult(SkParsePath::FromSVGString("M0,0zM10,0zM20,0z", &fMoveZfPath));
103 SkAssertResult(SkParsePath::FromSVGString("M0,0h25", &fDashedfPath));
caryclark6651a322015-09-09 13:20:49 -0700104 SkAssertResult(SkParsePath::FromSVGString("M 0 0 C 0 0 0 0 0 0", &fCubicPath));
105 SkAssertResult(SkParsePath::FromSVGString("M 0 0 Q 0 0 0 0", &fQuadPath));
106 SkAssertResult(SkParsePath::FromSVGString("M 0 0 L 0 0", &fLinePath));
caryclark5cb00a92015-08-26 09:04:55 -0700107
108 for (int i = 0; i < 3; ++i) {
109 fRefPath[0].addCircle(i * 10.f, 0, 5);
110 fRefPath[1].addCircle(i * 10.f, 0, 10);
111 fRefPath[2].addRect(i * 10.f - 4, -2, i * 10.f + 4, 6);
112 fRefPath[3].addRect(i * 10.f - 10, -10, i * 10.f + 10, 10);
113 }
114 }
115
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000116 SkString getName() const override { return SkString("zeroPath"); }
caryclark5cb00a92015-08-26 09:04:55 -0700117
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000118 SkISize getISize() override { return SkISize::Make(W, H * 2); }
caryclark5cb00a92015-08-26 09:04:55 -0700119
120 void onDraw(SkCanvas* canvas) override {
121 SkPaint fillPaint, strokePaint, dashPaint;
122 fillPaint.setAntiAlias(true);
123 strokePaint = fillPaint;
124 strokePaint.setStyle(SkPaint::kStroke_Style);
125 for (int i = 0; i < 2; ++i) {
Mike Reed9407e242019-02-15 16:13:57 -0500126 fillPaint.setAlphaf(1.0f);
127 strokePaint.setAlphaf(1.0f);
caryclark5cb00a92015-08-26 09:04:55 -0700128 strokePaint.setStrokeWidth(i ? 8.f : 10.f);
129 strokePaint.setStrokeCap(i ? SkPaint::kSquare_Cap : SkPaint::kRound_Cap);
130 canvas->save();
131 canvas->translate(10 + i * 100.f, 10);
132 canvas->drawPath(fMoveHfPath, strokePaint);
133 canvas->translate(0, 20);
134 canvas->drawPath(fMoveZfPath, strokePaint);
135 dashPaint = strokePaint;
136 const SkScalar intervals[] = { 0, 10 };
reeda4393342016-03-18 11:22:57 -0700137 dashPaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
caryclark5cb00a92015-08-26 09:04:55 -0700138 SkPath fillPath;
Kevin Lubickf5491282022-12-15 08:37:49 -0500139 skpathutils::FillPathWithPaint(fDashedfPath, dashPaint, &fillPath);
caryclark5cb00a92015-08-26 09:04:55 -0700140 canvas->translate(0, 20);
141 canvas->drawPath(fDashedfPath, dashPaint);
142 canvas->translate(0, 20);
143 canvas->drawPath(fRefPath[i * 2], fillPaint);
144 strokePaint.setStrokeWidth(20);
Mike Reed9407e242019-02-15 16:13:57 -0500145 strokePaint.setAlphaf(0.5f);
caryclark5cb00a92015-08-26 09:04:55 -0700146 canvas->translate(0, 50);
147 canvas->drawPath(fMoveHfPath, strokePaint);
148 canvas->translate(0, 30);
149 canvas->drawPath(fMoveZfPath, strokePaint);
150 canvas->translate(0, 30);
Mike Reed9407e242019-02-15 16:13:57 -0500151 fillPaint.setAlphaf(0.5f);
caryclark5cb00a92015-08-26 09:04:55 -0700152 canvas->drawPath(fRefPath[1 + i * 2], fillPaint);
caryclark6651a322015-09-09 13:20:49 -0700153 canvas->translate(0, 30);
154 canvas->drawPath(fCubicPath, strokePaint);
155 canvas->translate(0, 30);
156 canvas->drawPath(fQuadPath, strokePaint);
157 canvas->translate(0, 30);
158 canvas->drawPath(fLinePath, strokePaint);
caryclark5cb00a92015-08-26 09:04:55 -0700159 canvas->restore();
160 }
161 }
162
163private:
John Stiles7571f9e2020-09-02 22:42:33 -0400164 using INHERITED = skiagm::GM;
caryclark5cb00a92015-08-26 09:04:55 -0700165};
166
caryclark950305e2015-10-26 08:17:04 -0700167class TeenyStrokesGM : public skiagm::GM {
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000168 SkString getName() const override { return SkString("teenyStrokes"); }
caryclark950305e2015-10-26 08:17:04 -0700169
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000170 SkISize getISize() override { return SkISize::Make(W, H * 2); }
caryclark950305e2015-10-26 08:17:04 -0700171
172 static void line(SkScalar scale, SkCanvas* canvas, SkColor color) {
173 SkPaint p;
174 p.setAntiAlias(true);
175 p.setStyle(SkPaint::kStroke_Style);
176 p.setColor(color);
177 canvas->translate(50, 0);
Robert Phillipse9229532020-06-26 10:10:49 -0400178 canvas->save();
caryclark950305e2015-10-26 08:17:04 -0700179 p.setStrokeWidth(scale * 5);
Robert Phillipse9229532020-06-26 10:10:49 -0400180 canvas->scale(1 / scale, 1 / scale);
caryclark950305e2015-10-26 08:17:04 -0700181 canvas->drawLine(20 * scale, 20 * scale, 20 * scale, 100 * scale, p);
182 canvas->drawLine(20 * scale, 20 * scale, 100 * scale, 100 * scale, p);
183 canvas->restore();
184 }
185
186 void onDraw(SkCanvas* canvas) override {
187 line(0.00005f, canvas, SK_ColorBLACK);
188 line(0.000045f, canvas, SK_ColorRED);
189 line(0.0000035f, canvas, SK_ColorGREEN);
190 line(0.000003f, canvas, SK_ColorBLUE);
191 line(0.000002f, canvas, SK_ColorBLACK);
192 }
193private:
John Stiles7571f9e2020-09-02 22:42:33 -0400194 using INHERITED = skiagm::GM;
caryclark950305e2015-10-26 08:17:04 -0700195};
196
caryclarkb775e912015-11-30 13:47:11 -0800197DEF_SIMPLE_GM(CubicStroke, canvas, 384, 384) {
198 SkPaint p;
199 p.setAntiAlias(true);
200 p.setStyle(SkPaint::kStroke_Style);
201 p.setStrokeWidth(1.0720f);
Robert Phillipse9229532020-06-26 10:10:49 -0400202 SkPath path;
caryclarkb775e912015-11-30 13:47:11 -0800203 path.moveTo(-6000,-6000);
204 path.cubicTo(-3500,5500,-500,5500,2500,-6500);
205 canvas->drawPath(path, p);
206 p.setStrokeWidth(1.0721f);
207 canvas->translate(10, 10);
208 canvas->drawPath(path, p);
209 p.setStrokeWidth(1.0722f);
210 canvas->translate(10, 10);
211 canvas->drawPath(path, p);
212}
caryclark950305e2015-10-26 08:17:04 -0700213
caryclark57eecc12015-12-08 04:29:45 -0800214DEF_SIMPLE_GM(zerolinestroke, canvas, 90, 120) {
215 SkPaint paint;
216 paint.setStyle(SkPaint::kStroke_Style);
217 paint.setStrokeWidth(20);
218 paint.setAntiAlias(true);
219 paint.setStrokeCap(SkPaint::kRound_Cap);
220
221 SkPath path;
222 path.moveTo(30, 90);
223 path.lineTo(30, 90);
224 path.lineTo(60, 90);
225 path.lineTo(60, 90);
226 canvas->drawPath(path, paint);
227
228 path.reset();
229 path.moveTo(30, 30);
230 path.lineTo(60, 30);
231 canvas->drawPath(path, paint);
232
233 path.reset();
234 path.moveTo(30, 60);
235 path.lineTo(30, 60);
236 path.lineTo(60, 60);
237 canvas->drawPath(path, paint);
238}
239
caryclark40b7d3b2015-12-22 06:13:33 -0800240DEF_SIMPLE_GM(quadcap, canvas, 200, 200) {
241 SkPaint p;
242 p.setAntiAlias(true);
243 p.setStyle(SkPaint::kStroke_Style);
244 p.setStrokeWidth(0);
245 SkPath path;
246 SkPoint pts[] = {{105.738571f,13.126318f},
halcanary9d524f22016-03-29 09:03:52 -0700247 {105.738571f,13.126318f},
caryclark40b7d3b2015-12-22 06:13:33 -0800248 {123.753784f,1.f}};
249 SkVector tangent = pts[1] - pts[2];
250 tangent.normalize();
251 SkPoint pts2[3];
252 memcpy(pts2, pts, sizeof(pts));
253 const SkScalar capOutset = SK_ScalarPI / 8;
254 pts2[0].fX += tangent.fX * capOutset;
255 pts2[0].fY += tangent.fY * capOutset;
256 pts2[1].fX += tangent.fX * capOutset;
257 pts2[1].fY += tangent.fY * capOutset;
258 pts2[2].fX += -tangent.fX * capOutset;
259 pts2[2].fY += -tangent.fY * capOutset;
260 path.moveTo(pts2[0]);
261 path.quadTo(pts2[1], pts2[2]);
262 canvas->drawPath(path, p);
263
264 path.reset();
265 path.moveTo(pts[0]);
266 path.quadTo(pts[1], pts[2]);
267 p.setStrokeCap(SkPaint::kRound_Cap);
268 canvas->translate(30, 0);
269 canvas->drawPath(path, p);
270}
271
reed@google.com4384fab2012-06-05 16:14:23 +0000272class Strokes2GM : public skiagm::GM {
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000273 SkPath fPath;
caryclark63c684a2015-02-25 09:04:04 -0800274protected:
mtklein36352bf2015-03-25 18:17:31 -0700275 void onOnceBeforeDraw() override {
scroggof9d61012014-12-15 12:54:51 -0800276 SkRandom rand;
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000277 fPath.moveTo(0, 0);
278 for (int i = 0; i < 13; i++) {
279 SkScalar x = rand.nextUScalar1() * (W >> 1);
280 SkScalar y = rand.nextUScalar1() * (H >> 1);
281 fPath.lineTo(x, y);
282 }
283 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000284
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000285 SkString getName() const override { return SkString("strokes_poly"); }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000286
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000287 SkISize getISize() override { return SkISize::Make(W, H * 2); }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000288
mtklein36352bf2015-03-25 18:17:31 -0700289 void onDraw(SkCanvas* canvas) override {
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000290 canvas->drawColor(SK_ColorWHITE);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000291
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000292 SkPaint paint;
293 paint.setStyle(SkPaint::kStroke_Style);
294 paint.setStrokeWidth(SkIntToScalar(9)/2);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000295
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000296 for (int y = 0; y < 2; y++) {
297 paint.setAntiAlias(!!y);
298 SkAutoCanvasRestore acr(canvas, true);
299 canvas->translate(0, SH * y);
300 canvas->clipRect(SkRect::MakeLTRB(SkIntToScalar(2),
301 SkIntToScalar(2),
302 SW - SkIntToScalar(2),
303 SH - SkIntToScalar(2)));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000304
scroggof9d61012014-12-15 12:54:51 -0800305 SkRandom rand;
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000306 for (int i = 0; i < N/2; i++) {
307 SkRect r;
308 rnd_rect(&r, &paint, rand);
bungeman7438bfc2016-07-12 15:01:19 -0700309 canvas->rotate(SkIntToScalar(15), SW/2, SH/2);
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000310 canvas->drawPath(fPath, paint);
311 }
312 }
313 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000314
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000315private:
John Stiles7571f9e2020-09-02 22:42:33 -0400316 using INHERITED = skiagm::GM;
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000317};
318
319//////////////////////////////////////////////////////////////////////////////
320
reed@google.com4384fab2012-06-05 16:14:23 +0000321static SkRect inset(const SkRect& r) {
322 SkRect rr(r);
323 rr.inset(r.width()/10, r.height()/10);
324 return rr;
mike@reedtribe.orgf2c21cd2011-06-18 00:15:04 +0000325}
326
reed@google.com4384fab2012-06-05 16:14:23 +0000327class Strokes3GM : public skiagm::GM {
328 static void make0(SkPath* path, const SkRect& bounds, SkString* title) {
Mike Reed30bc5272019-11-22 18:34:02 +0000329 path->addRect(bounds, SkPathDirection::kCW);
330 path->addRect(inset(bounds), SkPathDirection::kCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000331 title->set("CW CW");
332 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000333
reed@google.com4384fab2012-06-05 16:14:23 +0000334 static void make1(SkPath* path, const SkRect& bounds, SkString* title) {
Mike Reed30bc5272019-11-22 18:34:02 +0000335 path->addRect(bounds, SkPathDirection::kCW);
336 path->addRect(inset(bounds), SkPathDirection::kCCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000337 title->set("CW CCW");
338 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000339
reed@google.com4384fab2012-06-05 16:14:23 +0000340 static void make2(SkPath* path, const SkRect& bounds, SkString* title) {
Mike Reed30bc5272019-11-22 18:34:02 +0000341 path->addOval(bounds, SkPathDirection::kCW);
342 path->addOval(inset(bounds), SkPathDirection::kCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000343 title->set("CW CW");
344 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000345
reed@google.com4384fab2012-06-05 16:14:23 +0000346 static void make3(SkPath* path, const SkRect& bounds, SkString* title) {
Mike Reed30bc5272019-11-22 18:34:02 +0000347 path->addOval(bounds, SkPathDirection::kCW);
348 path->addOval(inset(bounds), SkPathDirection::kCCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000349 title->set("CW CCW");
350 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000351
reed@google.com4384fab2012-06-05 16:14:23 +0000352 static void make4(SkPath* path, const SkRect& bounds, SkString* title) {
Mike Reed30bc5272019-11-22 18:34:02 +0000353 path->addRect(bounds, SkPathDirection::kCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000354 SkRect r = bounds;
355 r.inset(bounds.width() / 10, -bounds.height() / 10);
Mike Reed30bc5272019-11-22 18:34:02 +0000356 path->addOval(r, SkPathDirection::kCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000357 title->set("CW CW");
358 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000359
reed@google.com4384fab2012-06-05 16:14:23 +0000360 static void make5(SkPath* path, const SkRect& bounds, SkString* title) {
Mike Reed30bc5272019-11-22 18:34:02 +0000361 path->addRect(bounds, SkPathDirection::kCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000362 SkRect r = bounds;
363 r.inset(bounds.width() / 10, -bounds.height() / 10);
Mike Reed30bc5272019-11-22 18:34:02 +0000364 path->addOval(r, SkPathDirection::kCCW);
reed@google.com4384fab2012-06-05 16:14:23 +0000365 title->set("CW CCW");
366 }
367
368public:
369 Strokes3GM() {}
rmistry@google.comae933ce2012-08-23 18:19:56 +0000370
reed@google.com4384fab2012-06-05 16:14:23 +0000371protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000372 SkString getName() const override { return SkString("strokes3"); }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000373
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000374 SkISize getISize() override { return SkISize::Make(1500, 1500); }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000375
mtklein36352bf2015-03-25 18:17:31 -0700376 void onDraw(SkCanvas* canvas) override {
reed@google.com4384fab2012-06-05 16:14:23 +0000377 SkPaint origPaint;
378 origPaint.setAntiAlias(true);
379 origPaint.setStyle(SkPaint::kStroke_Style);
380 SkPaint fillPaint(origPaint);
381 fillPaint.setColor(SK_ColorRED);
382 SkPaint strokePaint(origPaint);
Mike Kleinea3f0142019-03-20 11:12:10 -0500383 strokePaint.setColor(ToolUtils::color_to_565(0xFF4444FF));
reed@google.com4384fab2012-06-05 16:14:23 +0000384
385 void (*procs[])(SkPath*, const SkRect&, SkString*) = {
386 make0, make1, make2, make3, make4, make5
387 };
388
caryclark37604572015-02-23 06:51:04 -0800389 canvas->translate(SkIntToScalar(20), SkIntToScalar(80));
reed@google.com4384fab2012-06-05 16:14:23 +0000390
391 SkRect bounds = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50));
392 SkScalar dx = bounds.width() * 4/3;
393 SkScalar dy = bounds.height() * 5;
394
Herb Derbyc37b3862022-06-21 09:49:17 -0400395 for (size_t i = 0; i < std::size(procs); ++i) {
reed@google.com4384fab2012-06-05 16:14:23 +0000396 SkPath orig;
397 SkString str;
398 procs[i](&orig, bounds, &str);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000399
reed@google.com4384fab2012-06-05 16:14:23 +0000400 canvas->save();
401 for (int j = 0; j < 13; ++j) {
402 strokePaint.setStrokeWidth(SK_Scalar1 * j * j);
403 canvas->drawPath(orig, strokePaint);
404 canvas->drawPath(orig, origPaint);
405 SkPath fill;
Kevin Lubickf5491282022-12-15 08:37:49 -0500406 skpathutils::FillPathWithPaint(orig, strokePaint, &fill);
reed@google.com4384fab2012-06-05 16:14:23 +0000407 canvas->drawPath(fill, fillPaint);
408 canvas->translate(dx + strokePaint.getStrokeWidth(), 0);
409 }
410 canvas->restore();
411 canvas->translate(0, dy);
412 }
413 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000414
reed@google.com4384fab2012-06-05 16:14:23 +0000415private:
John Stiles7571f9e2020-09-02 22:42:33 -0400416 using INHERITED = skiagm::GM;
reed@google.com4384fab2012-06-05 16:14:23 +0000417};
418
caryclark612f70d2015-05-19 11:05:37 -0700419class Strokes4GM : public skiagm::GM {
420public:
421 Strokes4GM() {}
422
423protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000424 SkString getName() const override { return SkString("strokes_zoomed"); }
caryclark612f70d2015-05-19 11:05:37 -0700425
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000426 SkISize getISize() override { return SkISize::Make(W, H * 2); }
caryclark612f70d2015-05-19 11:05:37 -0700427
428 void onDraw(SkCanvas* canvas) override {
429 SkPaint paint;
430 paint.setStyle(SkPaint::kStroke_Style);
431 paint.setStrokeWidth(0.055f);
halcanary9d524f22016-03-29 09:03:52 -0700432
caryclark612f70d2015-05-19 11:05:37 -0700433 canvas->scale(1000, 1000);
434 canvas->drawCircle(0, 2, 1.97f, paint);
435 }
436
437private:
John Stiles7571f9e2020-09-02 22:42:33 -0400438 using INHERITED = skiagm::GM;
caryclark612f70d2015-05-19 11:05:37 -0700439};
440
caryclark45398df2015-08-25 13:19:06 -0700441// Test stroking for curves that produce degenerate tangents when t is 0 or 1 (see bug 4191)
442class Strokes5GM : public skiagm::GM {
443public:
444 Strokes5GM() {}
445
446protected:
Leandro Lovisolo24fa2112023-08-15 19:05:17 +0000447 SkString getName() const override { return SkString("zero_control_stroke"); }
caryclark45398df2015-08-25 13:19:06 -0700448
Leandro Lovisolo8f023882023-08-15 21:13:52 +0000449 SkISize getISize() override { return SkISize::Make(W, H * 2); }
caryclark45398df2015-08-25 13:19:06 -0700450
451 void onDraw(SkCanvas* canvas) override {
452 SkPaint p;
453 p.setColor(SK_ColorRED);
454 p.setAntiAlias(true);
455 p.setStyle(SkPaint::kStroke_Style);
456 p.setStrokeWidth(40);
457 p.setStrokeCap(SkPaint::kButt_Cap);
458
459 SkPath path;
460 path.moveTo(157.474f,111.753f);
461 path.cubicTo(128.5f,111.5f,35.5f,29.5f,35.5f,29.5f);
462 canvas->drawPath(path, p);
463 path.reset();
464 path.moveTo(250, 50);
465 path.quadTo(280, 80, 280, 80);
466 canvas->drawPath(path, p);
467 path.reset();
468 path.moveTo(150, 50);
469 path.conicTo(180, 80, 180, 80, 0.707f);
470 canvas->drawPath(path, p);
471
472 path.reset();
473 path.moveTo(157.474f,311.753f);
474 path.cubicTo(157.474f,311.753f,85.5f,229.5f,35.5f,229.5f);
475 canvas->drawPath(path, p);
476 path.reset();
477 path.moveTo(280, 250);
478 path.quadTo(280, 250, 310, 280);
479 canvas->drawPath(path, p);
480 path.reset();
481 path.moveTo(180, 250);
482 path.conicTo(180, 250, 210, 280, 0.707f);
483 canvas->drawPath(path, p);
484 }
485
486private:
John Stiles7571f9e2020-09-02 22:42:33 -0400487 using INHERITED = skiagm::GM;
caryclark45398df2015-08-25 13:19:06 -0700488};
489
caryclark612f70d2015-05-19 11:05:37 -0700490
reed@google.com4384fab2012-06-05 16:14:23 +0000491//////////////////////////////////////////////////////////////////////////////
492
scroggo96f16e82015-12-10 13:31:59 -0800493DEF_GM( return new StrokesGM; )
494DEF_GM( return new Strokes2GM; )
495DEF_GM( return new Strokes3GM; )
496DEF_GM( return new Strokes4GM; )
497DEF_GM( return new Strokes5GM; )
caryclark5cb00a92015-08-26 09:04:55 -0700498
halcanary385fe4d2015-08-26 13:07:48 -0700499DEF_GM( return new ZeroLenStrokesGM; )
caryclark950305e2015-10-26 08:17:04 -0700500DEF_GM( return new TeenyStrokesGM; )
Cary Clark0b1df4b2017-12-13 12:47:15 -0500501
502DEF_SIMPLE_GM(zerolinedash, canvas, 256, 256) {
503 canvas->clear(SK_ColorWHITE);
504
505 SkPaint paint;
506 paint.setColor(SkColorSetARGB(255, 0, 0, 0));
507 paint.setStrokeWidth(11);
508 paint.setStrokeCap(SkPaint::kRound_Cap);
509 paint.setStrokeJoin(SkPaint::kBevel_Join);
510
511 SkScalar dash_pattern[] = {1, 5};
512 paint.setPathEffect(SkDashPathEffect::Make(dash_pattern, 2, 0));
513
514 canvas->drawLine(100, 100, 100, 100, paint);
515}
Greg Daniel9838b492017-12-21 14:55:00 +0000516
517#ifdef PDF_IS_FIXED_SO_THIS_DOESNT_BREAK_IT
518DEF_SIMPLE_GM(longrect_dash, canvas, 250, 250) {
519 canvas->clear(SK_ColorWHITE);
520
521 SkPaint paint;
522 paint.setColor(SkColorSetARGB(255, 0, 0, 0));
523 paint.setStrokeWidth(5);
524 paint.setStrokeCap(SkPaint::kRound_Cap);
525 paint.setStrokeJoin(SkPaint::kBevel_Join);
526 paint.setStyle(SkPaint::kStroke_Style);
527 SkScalar dash_pattern[] = {1, 5};
528 paint.setPathEffect(SkDashPathEffect::Make(dash_pattern, 2, 0));
529 // try all combinations of stretching bounds
530 for (auto left : { 20.f, -100001.f } ) {
531 for (auto top : { 20.f, -100001.f } ) {
532 for (auto right : { 40.f, 100001.f } ) {
533 for (auto bottom : { 40.f, 100001.f } ) {
534 canvas->save();
535 canvas->clipRect({10, 10, 50, 50});
536 canvas->drawRect({left, top, right, bottom}, paint);
537 canvas->restore();
538 canvas->translate(60, 0);
539 }
540 }
541 canvas->translate(-60 * 4, 60);
542 }
543 }
544}
545#endif
Tyler Denniston966fb692021-05-25 09:11:59 -0400546
547DEF_SIMPLE_GM(inner_join_geometry, canvas, 1000, 700) {
548 // These paths trigger cases where we must add inner join geometry.
549 // skbug.com/11964
550 const SkPoint pathPoints[] = {
551 /*moveTo*/ /*lineTo*/ /*lineTo*/
552 {119, 71}, {129, 151}, {230, 24},
553 {200, 144}, {129, 151}, {230, 24},
554 {192, 176}, {224, 175}, {281, 103},
555 {233, 205}, {224, 175}, {281, 103},
556 {121, 216}, {234, 189}, {195, 147},
557 {141, 216}, {254, 189}, {238, 250},
558 {159, 202}, {269, 197}, {289, 165},
559 {159, 202}, {269, 197}, {287, 227},
560 };
561
562 SkPaint pathPaint;
563 pathPaint.setStroke(true);
564 pathPaint.setAntiAlias(true);
565 pathPaint.setStrokeWidth(100);
566
567 SkPaint skeletonPaint;
568 skeletonPaint.setStroke(true);
569 skeletonPaint.setAntiAlias(true);
570 skeletonPaint.setStrokeWidth(0);
571 skeletonPaint.setColor(SK_ColorRED);
572
573 canvas->translate(0, 50);
Herb Derbyc37b3862022-06-21 09:49:17 -0400574 for (size_t i = 0; i < std::size(pathPoints) / 3; i++) {
Tyler Denniston966fb692021-05-25 09:11:59 -0400575 auto path = SkPath::Polygon(pathPoints + i * 3, 3, false);
576 canvas->drawPath(path, pathPaint);
577
578 SkPath fillPath;
Kevin Lubickf5491282022-12-15 08:37:49 -0500579 skpathutils::FillPathWithPaint(path, pathPaint, &fillPath);
Tyler Denniston966fb692021-05-25 09:11:59 -0400580 canvas->drawPath(fillPath, skeletonPaint);
581
582 canvas->translate(200, 0);
583 if ((i + 1) % 4 == 0) {
584 canvas->translate(-800, 200);
585 }
586 }
587}
Michael Ludwig9cd9d0f2021-08-03 15:05:26 -0400588
589DEF_SIMPLE_GM(skbug12244, canvas, 150, 150) {
590 // Should look like a stroked triangle; these vertices are the results of the SkStroker
591 // but we draw as a filled path in order to highlight that it's the GPU triangulating path
592 // renderer that's the source of the problem, and not the stroking operation. The original
593 // path was a simple:
594 // m(0,0), l(100, 40), l(0, 80), l(0,0) with a stroke width of 15px
595 SkPath path;
596 path.moveTo(2.7854299545288085938, -6.9635753631591796875);
597 path.lineTo( 120.194366455078125, 40);
598 path.lineTo(-7.5000004768371582031, 91.07775115966796875);
599 path.lineTo(-7.5000004768371582031, -11.077748298645019531);
600 path.lineTo(2.7854299545288085938, -6.9635753631591796875);
601 path.moveTo(-2.7854299545288085938, 6.9635753631591796875);
602 path.lineTo( 0, 0);
603 path.lineTo( 7.5, 0);
604 path.lineTo(7.5000004768371582031, 68.92224884033203125);
605 path.lineTo( 79.805633544921875, 40);
606 path.lineTo(-2.7854299545288085938, 6.9635753631591796875);
607
608 SkPaint p;
609 p.setColor(SK_ColorGREEN);
610
611 canvas->translate(20.f, 20.f);
612 canvas->drawPath(path, p);
613}