blob: 3f03843f38c60e2176e2e6a1c463549ab6b5f960 [file] [log] [blame]
reed@google.com35a81df2012-05-04 21:49:27 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkColor.h"
11#include "include/core/SkFont.h"
12#include "include/core/SkMatrix.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkPaint.h"
Mike Reed06d7c9d2020-08-26 12:56:51 -040014#include "include/core/SkPathBuilder.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040015#include "include/core/SkPathEffect.h"
16#include "include/core/SkPoint.h"
17#include "include/core/SkRect.h"
18#include "include/core/SkScalar.h"
19#include "include/core/SkSize.h"
20#include "include/core/SkString.h"
21#include "include/core/SkTypeface.h"
22#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "include/effects/SkDashPathEffect.h"
24#include "tools/ToolUtils.h"
reed@google.com35a81df2012-05-04 21:49:27 +000025
Ben Wagner7fde8e12019-05-01 17:28:53 -040026#include <math.h>
27#include <initializer_list>
28
reed@google.comde1837b2012-05-21 16:47:43 +000029static void drawline(SkCanvas* canvas, int on, int off, const SkPaint& paint,
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +000030 SkScalar finalX = SkIntToScalar(600), SkScalar finalY = SkIntToScalar(0),
halcanary9d524f22016-03-29 09:03:52 -070031 SkScalar phase = SkIntToScalar(0),
robertphillips9f2251c2014-11-04 13:33:50 -080032 SkScalar startX = SkIntToScalar(0), SkScalar startY = SkIntToScalar(0)) {
reed@google.com35a81df2012-05-04 21:49:27 +000033 SkPaint p(paint);
34
35 const SkScalar intervals[] = {
36 SkIntToScalar(on),
37 SkIntToScalar(off),
38 };
39
reeda4393342016-03-18 11:22:57 -070040 p.setPathEffect(SkDashPathEffect::Make(intervals, 2, phase));
robertphillips9f2251c2014-11-04 13:33:50 -080041 canvas->drawLine(startX, startY, finalX, finalY, p);
reed@google.comde1837b2012-05-21 16:47:43 +000042}
43
44// earlier bug stopped us from drawing very long single-segment dashes, because
45// SkPathMeasure was skipping very small delta-T values (nearlyzero). This is
46// now fixes, so this giant dash should appear.
47static void show_giant_dash(SkCanvas* canvas) {
48 SkPaint paint;
49
50 drawline(canvas, 1, 1, paint, SkIntToScalar(20 * 1000));
reed@google.com35a81df2012-05-04 21:49:27 +000051}
52
egdaniel21402e32014-11-05 05:02:27 -080053static void show_zero_len_dash(SkCanvas* canvas) {
54 SkPaint paint;
55
56 drawline(canvas, 2, 2, paint, SkIntToScalar(0));
Mike Reed19630092020-05-18 21:25:44 -040057 paint.setStroke(true);
egdaniel21402e32014-11-05 05:02:27 -080058 paint.setStrokeWidth(SkIntToScalar(2));
59 canvas->translate(0, SkIntToScalar(20));
60 drawline(canvas, 4, 4, paint, SkIntToScalar(0));
61}
62
reed@google.com21384df2012-05-18 17:59:08 +000063class DashingGM : public skiagm::GM {
Hal Canaryfa3305a2019-07-18 12:36:54 -040064 SkString onShortName() override { return SkString("dashing"); }
reed@google.com35a81df2012-05-04 21:49:27 +000065
Hal Canaryfa3305a2019-07-18 12:36:54 -040066 SkISize onISize() override { return {640, 340}; }
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000067
Hal Canaryfa3305a2019-07-18 12:36:54 -040068 void onDraw(SkCanvas* canvas) override {
John Stilesdbcf6802020-05-18 10:58:51 -040069 struct Intervals {
reed@google.com35a81df2012-05-04 21:49:27 +000070 int fOnInterval;
71 int fOffInterval;
reed@google.com35a81df2012-05-04 21:49:27 +000072 };
rmistry@google.comae933ce2012-08-23 18:19:56 +000073
reed@google.com35a81df2012-05-04 21:49:27 +000074 SkPaint paint;
Mike Reed19630092020-05-18 21:25:44 -040075 paint.setStroke(true);
reed@google.com35a81df2012-05-04 21:49:27 +000076
77 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
78 canvas->translate(0, SK_ScalarHalf);
reed@google.com35a81df2012-05-04 21:49:27 +000079 for (int width = 0; width <= 2; ++width) {
John Stilesdbcf6802020-05-18 10:58:51 -040080 for (const Intervals& data : {Intervals{1, 1},
81 Intervals{4, 1}}) {
82 for (bool aa : {false, true}) {
reed@google.com35a81df2012-05-04 21:49:27 +000083 int w = width * width * width;
John Stilesdbcf6802020-05-18 10:58:51 -040084 paint.setAntiAlias(aa);
reed@google.com35a81df2012-05-04 21:49:27 +000085 paint.setStrokeWidth(SkIntToScalar(w));
rmistry@google.comae933ce2012-08-23 18:19:56 +000086
reed@google.com35a81df2012-05-04 21:49:27 +000087 int scale = w ? w : 1;
88
John Stilesdbcf6802020-05-18 10:58:51 -040089 drawline(canvas, data.fOnInterval * scale, data.fOffInterval * scale,
reed@google.com35a81df2012-05-04 21:49:27 +000090 paint);
91 canvas->translate(0, SkIntToScalar(20));
92 }
93 }
94 }
rmistry@google.comae933ce2012-08-23 18:19:56 +000095
reed@google.comde1837b2012-05-21 16:47:43 +000096 show_giant_dash(canvas);
egdaniel21402e32014-11-05 05:02:27 -080097 canvas->translate(0, SkIntToScalar(20));
98 show_zero_len_dash(canvas);
egdanielc00389e2015-10-05 08:11:49 -070099 canvas->translate(0, SkIntToScalar(20));
100 // Draw 0 on, 0 off dashed line
101 paint.setStrokeWidth(SkIntToScalar(8));
102 drawline(canvas, 0, 0, paint);
reed@google.com35a81df2012-05-04 21:49:27 +0000103 }
reed@google.com21384df2012-05-18 17:59:08 +0000104};
reed@google.com35a81df2012-05-04 21:49:27 +0000105
reed@google.com21384df2012-05-18 17:59:08 +0000106///////////////////////////////////////////////////////////////////////////////
107
Mike Reed06d7c9d2020-08-26 12:56:51 -0400108static SkPath make_unit_star(int n) {
reed@google.com21384df2012-05-18 17:59:08 +0000109 SkScalar rad = -SK_ScalarPI / 2;
110 const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000111
Mike Reed06d7c9d2020-08-26 12:56:51 -0400112 SkPathBuilder b;
113 b.moveTo(0, -SK_Scalar1);
reed@google.com21384df2012-05-18 17:59:08 +0000114 for (int i = 1; i < n; i++) {
115 rad += drad;
Mike Reed06d7c9d2020-08-26 12:56:51 -0400116 b.lineTo(SkScalarCos(rad), SkScalarSin(rad));
reed@google.com21384df2012-05-18 17:59:08 +0000117 }
Mike Reed06d7c9d2020-08-26 12:56:51 -0400118 return b.close().detach();
reed@google.com21384df2012-05-18 17:59:08 +0000119}
120
Mike Reed06d7c9d2020-08-26 12:56:51 -0400121static SkPath make_path_line(const SkRect& bounds) {
122 return SkPathBuilder().moveTo(bounds.left(), bounds.top())
123 .lineTo(bounds.right(), bounds.bottom())
124 .detach();
reed@google.com21384df2012-05-18 17:59:08 +0000125}
126
Mike Reed06d7c9d2020-08-26 12:56:51 -0400127static SkPath make_path_rect(const SkRect& bounds) {
128 return SkPath::Rect(bounds);
reed@google.com21384df2012-05-18 17:59:08 +0000129}
130
Mike Reed06d7c9d2020-08-26 12:56:51 -0400131static SkPath make_path_oval(const SkRect& bounds) {
132 return SkPath::Oval(bounds);
reed@google.com21384df2012-05-18 17:59:08 +0000133}
134
Mike Reed06d7c9d2020-08-26 12:56:51 -0400135static SkPath make_path_star(const SkRect& bounds) {
136 SkPath path = make_unit_star(5);
Mike Reed2ac6ce82021-01-15 12:26:22 -0500137 SkMatrix matrix = SkMatrix::RectToRect(path.getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
Mike Reed06d7c9d2020-08-26 12:56:51 -0400138 return path.makeTransform(matrix);
reed@google.com21384df2012-05-18 17:59:08 +0000139}
140
141class Dashing2GM : public skiagm::GM {
Hal Canaryfa3305a2019-07-18 12:36:54 -0400142 SkString onShortName() override { return SkString("dashing2"); }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000143
Hal Canaryfa3305a2019-07-18 12:36:54 -0400144 SkISize onISize() override { return {640, 480}; }
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000145
Hal Canaryfa3305a2019-07-18 12:36:54 -0400146 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -0700147 constexpr int gIntervals[] = {
reed@google.com21384df2012-05-18 17:59:08 +0000148 3, // 3 dashes: each count [0] followed by intervals [1..count]
149 2, 10, 10,
150 4, 20, 5, 5, 5,
151 2, 2, 2
152 };
153
Mike Reed06d7c9d2020-08-26 12:56:51 -0400154 SkPath (*gProc[])(const SkRect&) = {
reed@google.com21384df2012-05-18 17:59:08 +0000155 make_path_line, make_path_rect, make_path_oval, make_path_star,
156 };
rmistry@google.comae933ce2012-08-23 18:19:56 +0000157
reed@google.com21384df2012-05-18 17:59:08 +0000158 SkPaint paint;
159 paint.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400160 paint.setStroke(true);
reed@google.com21384df2012-05-18 17:59:08 +0000161 paint.setStrokeWidth(SkIntToScalar(6));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000162
reed@google.com21384df2012-05-18 17:59:08 +0000163 SkRect bounds = SkRect::MakeWH(SkIntToScalar(120), SkIntToScalar(120));
164 bounds.offset(SkIntToScalar(20), SkIntToScalar(20));
165 SkScalar dx = bounds.width() * 4 / 3;
166 SkScalar dy = bounds.height() * 4 / 3;
167
168 const int* intervals = &gIntervals[1];
169 for (int y = 0; y < gIntervals[0]; ++y) {
170 SkScalar vals[SK_ARRAY_COUNT(gIntervals)]; // more than enough
171 int count = *intervals++;
172 for (int i = 0; i < count; ++i) {
173 vals[i] = SkIntToScalar(*intervals++);
174 }
175 SkScalar phase = vals[0] / 2;
reeda4393342016-03-18 11:22:57 -0700176 paint.setPathEffect(SkDashPathEffect::Make(vals, count, phase));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000177
reed@google.com21384df2012-05-18 17:59:08 +0000178 for (size_t x = 0; x < SK_ARRAY_COUNT(gProc); ++x) {
179 SkPath path;
180 SkRect r = bounds;
181 r.offset(x * dx, y * dy);
Mike Reed06d7c9d2020-08-26 12:56:51 -0400182 canvas->drawPath(gProc[x](r), paint);
reed@google.com21384df2012-05-18 17:59:08 +0000183 }
184 }
185 }
reed@google.com35a81df2012-05-04 21:49:27 +0000186};
187
188//////////////////////////////////////////////////////////////////////////////
189
robertphillips@google.com629ab542012-11-28 17:18:11 +0000190// Test out the on/off line dashing Chrome if fond of
191class Dashing3GM : public skiagm::GM {
Hal Canaryfa3305a2019-07-18 12:36:54 -0400192 SkString onShortName() override { return SkString("dashing3"); }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000193
Hal Canaryfa3305a2019-07-18 12:36:54 -0400194 SkISize onISize() override { return {640, 480}; }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000195
196 // Draw a 100x100 block of dashed lines. The horizontal ones are BW
197 // while the vertical ones are AA.
skia.committer@gmail.com73b140a2012-12-05 02:01:21 +0000198 void drawDashedLines(SkCanvas* canvas,
199 SkScalar lineLength,
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000200 SkScalar phase,
201 SkScalar dashLength,
202 int strokeWidth,
203 bool circles) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000204 SkPaint p;
205 p.setColor(SK_ColorBLACK);
Mike Reed19630092020-05-18 21:25:44 -0400206 p.setStroke(true);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000207 p.setStrokeWidth(SkIntToScalar(strokeWidth));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000208
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000209 if (circles) {
210 p.setStrokeCap(SkPaint::kRound_Cap);
211 }
212
213 SkScalar intervals[2] = { dashLength, dashLength };
robertphillips@google.com629ab542012-11-28 17:18:11 +0000214
reeda4393342016-03-18 11:22:57 -0700215 p.setPathEffect(SkDashPathEffect::Make(intervals, 2, phase));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000216
217 SkPoint pts[2];
218
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000219 for (int y = 0; y < 100; y += 10*strokeWidth) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000220 pts[0].set(0, SkIntToScalar(y));
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000221 pts[1].set(lineLength, SkIntToScalar(y));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000222
223 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
224 }
225
226 p.setAntiAlias(true);
227
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000228 for (int x = 0; x < 100; x += 14*strokeWidth) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000229 pts[0].set(SkIntToScalar(x), 0);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000230 pts[1].set(SkIntToScalar(x), lineLength);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000231
232 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
233 }
234 }
235
Hal Canaryfa3305a2019-07-18 12:36:54 -0400236 void onDraw(SkCanvas* canvas) override {
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000237 // 1on/1off 1x1 squares with phase of 0 - points fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000238 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000239 canvas->translate(2, 0);
240 this->drawDashedLines(canvas, 100, 0, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000241 canvas->restore();
242
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000243 // 1on/1off 1x1 squares with phase of .5 - rects fastpath (due to partial squares)
robertphillips@google.com629ab542012-11-28 17:18:11 +0000244 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000245 canvas->translate(112, 0);
246 this->drawDashedLines(canvas, 100, SK_ScalarHalf, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000247 canvas->restore();
248
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000249 // 1on/1off 1x1 squares with phase of 1 - points fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000250 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000251 canvas->translate(222, 0);
252 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000253 canvas->restore();
254
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000255 // 1on/1off 1x1 squares with phase of 1 and non-integer length - rects fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000256 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000257 canvas->translate(332, 0);
reed@google.com140d7282013-01-07 20:25:04 +0000258 this->drawDashedLines(canvas, 99.5f, SK_ScalarHalf, SK_Scalar1, 1, false);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000259 canvas->restore();
260
robertphillips@google.com5c4d5582013-01-15 12:53:31 +0000261 // 255on/255off 1x1 squares with phase of 0 - rects fast path
262 canvas->save();
263 canvas->translate(446, 0);
264 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(255), 1, false);
265 canvas->restore();
266
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000267 // 1on/1off 3x3 squares with phase of 0 - points fast path
268 canvas->save();
269 canvas->translate(2, 110);
270 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, false);
271 canvas->restore();
272
273 // 1on/1off 3x3 squares with phase of 1.5 - rects fast path
274 canvas->save();
275 canvas->translate(112, 110);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000276 this->drawDashedLines(canvas, 100, 1.5f, SkIntToScalar(3), 3, false);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000277 canvas->restore();
278
279 // 1on/1off 1x1 circles with phase of 1 - no fast path yet
280 canvas->save();
281 canvas->translate(2, 220);
282 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, true);
283 canvas->restore();
284
285 // 1on/1off 3x3 circles with phase of 1 - no fast path yet
286 canvas->save();
287 canvas->translate(112, 220);
288 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, true);
289 canvas->restore();
290
291 // 1on/1off 1x1 squares with rotation - should break fast path
292 canvas->save();
293 canvas->translate(332+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000294 canvas->rotate(45);
295 canvas->translate(-50, -50);
296
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000297 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000298 canvas->restore();
299
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000300 // 3on/3off 3x1 rects - should use rect fast path regardless of phase
301 for (int phase = 0; phase <= 3; ++phase) {
302 canvas->save();
skia.committer@gmail.com73b140a2012-12-05 02:01:21 +0000303 canvas->translate(SkIntToScalar(phase*110+2),
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000304 SkIntToScalar(330));
305 this->drawDashedLines(canvas, 100, SkIntToScalar(phase), SkIntToScalar(3), 1, false);
306 canvas->restore();
307 }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000308 }
309
310};
311
312//////////////////////////////////////////////////////////////////////////////
313
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000314class Dashing4GM : public skiagm::GM {
Hal Canaryfa3305a2019-07-18 12:36:54 -0400315 SkString onShortName() override { return SkString("dashing4"); }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000316
Hal Canaryfa3305a2019-07-18 12:36:54 -0400317 SkISize onISize() override { return {640, 1100}; }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000318
Hal Canaryfa3305a2019-07-18 12:36:54 -0400319 void onDraw(SkCanvas* canvas) override {
John Stilesdbcf6802020-05-18 10:58:51 -0400320 struct Intervals {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000321 int fOnInterval;
322 int fOffInterval;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000323 };
324
325 SkPaint paint;
Mike Reed19630092020-05-18 21:25:44 -0400326 paint.setStroke(true);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000327
328 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
Greg Daniel95581bb2017-06-30 10:36:38 -0400329 canvas->translate(SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000330
331 for (int width = 0; width <= 2; ++width) {
John Stilesdbcf6802020-05-18 10:58:51 -0400332 for (const Intervals& data : {Intervals{1, 1},
333 Intervals{4, 2},
Chris Dalton06b52ad2020-12-15 10:01:35 -0700334 Intervals{0, 4}}) { // test for zero length on interval.
335 // zero length intervals should draw
336 // a line of squares or circles
John Stilesdbcf6802020-05-18 10:58:51 -0400337 for (bool aa : {false, true}) {
338 for (auto cap : {SkPaint::kRound_Cap, SkPaint::kSquare_Cap}) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000339 int w = width * width * width;
John Stilesdbcf6802020-05-18 10:58:51 -0400340 paint.setAntiAlias(aa);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000341 paint.setStrokeWidth(SkIntToScalar(w));
John Stilesdbcf6802020-05-18 10:58:51 -0400342 paint.setStrokeCap(cap);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000343
344 int scale = w ? w : 1;
345
John Stilesdbcf6802020-05-18 10:58:51 -0400346 drawline(canvas, data.fOnInterval * scale, data.fOffInterval * scale,
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000347 paint);
348 canvas->translate(0, SkIntToScalar(20));
349 }
350 }
351 }
352 }
353
354 for (int aa = 0; aa <= 1; ++aa) {
355 paint.setAntiAlias(SkToBool(aa));
356 paint.setStrokeWidth(8.f);
357 paint.setStrokeCap(SkPaint::kSquare_Cap);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000358 // Single dash element that is cut off at start and end
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000359 drawline(canvas, 32, 16, paint, 20.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000360 canvas->translate(0, SkIntToScalar(20));
361
362 // Two dash elements where each one is cut off at beginning and end respectively
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000363 drawline(canvas, 32, 16, paint, 56.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000364 canvas->translate(0, SkIntToScalar(20));
365
366 // Many dash elements where first and last are cut off at beginning and end respectively
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000367 drawline(canvas, 32, 16, paint, 584.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000368 canvas->translate(0, SkIntToScalar(20));
369
370 // Diagonal dash line where src pnts are not axis aligned (as apposed to being diagonal from
371 // a canvas rotation)
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000372 drawline(canvas, 32, 16, paint, 600.f, 30.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000373 canvas->translate(0, SkIntToScalar(20));
374
375 // Case where only the off interval exists on the line. Thus nothing should be drawn
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000376 drawline(canvas, 32, 16, paint, 8.f, 0.f, 40.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000377 canvas->translate(0, SkIntToScalar(20));
378 }
Greg Daniel5fb30562017-06-29 12:27:48 -0400379
380 // Test overlapping circles.
381 canvas->translate(SkIntToScalar(5), SkIntToScalar(20));
382 paint.setAntiAlias(true);
383 paint.setStrokeCap(SkPaint::kRound_Cap);
384 paint.setColor(0x44000000);
385 paint.setStrokeWidth(40);
386 drawline(canvas, 0, 30, paint);
387
388 canvas->translate(0, SkIntToScalar(50));
389 paint.setStrokeCap(SkPaint::kSquare_Cap);
390 drawline(canvas, 0, 30, paint);
Greg Danielc96f9b52017-12-07 15:00:06 -0500391
392 // Test we draw the cap when the line length is zero.
393 canvas->translate(0, SkIntToScalar(50));
394 paint.setStrokeCap(SkPaint::kRound_Cap);
395 paint.setColor(0xFF000000);
396 paint.setStrokeWidth(11);
397 drawline(canvas, 0, 30, paint, 0);
398
399 canvas->translate(SkIntToScalar(100), 0);
400 drawline(canvas, 1, 30, paint, 0);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000401 }
402};
403
404//////////////////////////////////////////////////////////////////////////////
405
robertphillips9f2251c2014-11-04 13:33:50 -0800406class Dashing5GM : public skiagm::GM {
407public:
408 Dashing5GM(bool doAA) : fDoAA(doAA) {}
reed@google.com35a81df2012-05-04 21:49:27 +0000409
Hal Canaryfa3305a2019-07-18 12:36:54 -0400410private:
mtklein36352bf2015-03-25 18:17:31 -0700411 bool runAsBench() const override { return true; }
mtkleincf5d9c92015-01-23 10:31:45 -0800412
Hal Canaryfa3305a2019-07-18 12:36:54 -0400413 SkString onShortName() override { return SkString(fDoAA ? "dashing5_aa" : "dashing5_bw"); }
robertphillips9f2251c2014-11-04 13:33:50 -0800414
Hal Canaryfa3305a2019-07-18 12:36:54 -0400415 SkISize onISize() override { return {400, 200}; }
robertphillips9f2251c2014-11-04 13:33:50 -0800416
mtklein36352bf2015-03-25 18:17:31 -0700417 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -0700418 constexpr int kOn = 4;
419 constexpr int kOff = 4;
420 constexpr int kIntervalLength = kOn + kOff;
robertphillips9f2251c2014-11-04 13:33:50 -0800421
mtkleindbfd7ab2016-09-01 11:24:54 -0700422 constexpr SkColor gColors[kIntervalLength] = {
robertphillips9f2251c2014-11-04 13:33:50 -0800423 SK_ColorRED,
424 SK_ColorGREEN,
425 SK_ColorBLUE,
426 SK_ColorCYAN,
427 SK_ColorMAGENTA,
428 SK_ColorYELLOW,
429 SK_ColorGRAY,
430 SK_ColorDKGRAY
431 };
432
433 SkPaint paint;
Mike Reed19630092020-05-18 21:25:44 -0400434 paint.setStroke(true);
robertphillips9f2251c2014-11-04 13:33:50 -0800435
436 paint.setAntiAlias(fDoAA);
437
438 SkMatrix rot;
439 rot.setRotate(90);
440 SkASSERT(rot.rectStaysRect());
441
442 canvas->concat(rot);
443
444 int sign; // used to toggle the direction of the lines
445 int phase = 0;
446
447 for (int x = 0; x < 200; x += 10) {
448 paint.setStrokeWidth(SkIntToScalar(phase+1));
449 paint.setColor(gColors[phase]);
450 sign = (x % 20) ? 1 : -1;
halcanary9d524f22016-03-29 09:03:52 -0700451 drawline(canvas, kOn, kOff, paint,
452 SkIntToScalar(x), -sign * SkIntToScalar(10003),
robertphillips9f2251c2014-11-04 13:33:50 -0800453 SkIntToScalar(phase),
454 SkIntToScalar(x), sign * SkIntToScalar(10003));
455 phase = (phase + 1) % kIntervalLength;
456 }
457
458 for (int y = -400; y < 0; y += 10) {
459 paint.setStrokeWidth(SkIntToScalar(phase+1));
460 paint.setColor(gColors[phase]);
461 sign = (y % 20) ? 1 : -1;
halcanary9d524f22016-03-29 09:03:52 -0700462 drawline(canvas, kOn, kOff, paint,
463 -sign * SkIntToScalar(10003), SkIntToScalar(y),
robertphillips9f2251c2014-11-04 13:33:50 -0800464 SkIntToScalar(phase),
465 sign * SkIntToScalar(10003), SkIntToScalar(y));
466 phase = (phase + 1) % kIntervalLength;
467 }
468 }
469
470private:
471 bool fDoAA;
472};
473
reed6dc14aa2016-04-11 07:46:38 -0700474DEF_SIMPLE_GM(longpathdash, canvas, 612, 612) {
caryclarkf97aa742015-12-18 07:03:13 -0800475 SkPath lines;
476 for (int x = 32; x < 256; x += 16) {
477 for (SkScalar a = 0; a < 3.141592f * 2; a += 0.03141592f) {
478 SkPoint pts[2] = {
479 { 256 + (float) sin(a) * x,
480 256 + (float) cos(a) * x },
481 { 256 + (float) sin(a + 3.141592 / 3) * (x + 64),
482 256 + (float) cos(a + 3.141592 / 3) * (x + 64) }
483 };
484 lines.moveTo(pts[0]);
485 for (SkScalar i = 0; i < 1; i += 0.05f) {
486 lines.lineTo(pts[0].fX * (1 - i) + pts[1].fX * i,
487 pts[0].fY * (1 - i) + pts[1].fY * i);
488 }
489 }
490 }
491 SkPaint p;
492 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400493 p.setStroke(true);
caryclarkf97aa742015-12-18 07:03:13 -0800494 p.setStrokeWidth(1);
495 const SkScalar intervals[] = { 1, 1 };
reeda4393342016-03-18 11:22:57 -0700496 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
Ben Wagner63fd7602017-10-09 15:45:33 -0400497
reed6dc14aa2016-04-11 07:46:38 -0700498 canvas->translate(50, 50);
caryclarkf97aa742015-12-18 07:03:13 -0800499 canvas->drawPath(lines, p);
500}
501
caryclark70e6d602016-01-30 10:11:21 -0800502DEF_SIMPLE_GM(longlinedash, canvas, 512, 512) {
503 SkPaint p;
504 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400505 p.setStroke(true);
caryclark70e6d602016-01-30 10:11:21 -0800506 p.setStrokeWidth(80);
507
508 const SkScalar intervals[] = { 2, 2 };
reeda4393342016-03-18 11:22:57 -0700509 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
caryclark70e6d602016-01-30 10:11:21 -0800510 canvas->drawRect(SkRect::MakeXYWH(-10000, 100, 20000, 20), p);
511}
512
Robert Phillipsacc6b152021-02-10 11:54:35 -0500513DEF_SIMPLE_GM(dashbigrects, canvas, 256, 256) {
514 SkRandom rand;
515
516 constexpr int kHalfStrokeWidth = 8;
517 constexpr int kOnOffInterval = 2*kHalfStrokeWidth;
518
519 canvas->clear(SkColors::kBlack);
520
521 SkPaint p;
522 p.setAntiAlias(true);
523 p.setStroke(true);
524 p.setStrokeWidth(2*kHalfStrokeWidth);
525 p.setStrokeCap(SkPaint::kButt_Cap);
526
527 constexpr SkScalar intervals[] = { kOnOffInterval, kOnOffInterval };
528 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
529
530 constexpr float gWidthHeights[] = {
531 1000000000.0f * kOnOffInterval + kOnOffInterval/2.0f,
532 1000000.0f * kOnOffInterval + kOnOffInterval/2.0f,
533 1000.0f * kOnOffInterval + kOnOffInterval/2.0f,
534 100.0f * kOnOffInterval + kOnOffInterval/2.0f,
535 10.0f * kOnOffInterval + kOnOffInterval/2.0f,
536 9.0f * kOnOffInterval + kOnOffInterval/2.0f,
537 8.0f * kOnOffInterval + kOnOffInterval/2.0f,
538 7.0f * kOnOffInterval + kOnOffInterval/2.0f,
539 6.0f * kOnOffInterval + kOnOffInterval/2.0f,
540 5.0f * kOnOffInterval + kOnOffInterval/2.0f,
541 4.0f * kOnOffInterval + kOnOffInterval/2.0f,
542 };
543
544 for (size_t i = 0; i < SK_ARRAY_COUNT(gWidthHeights); ++i) {
545 p.setColor(ToolUtils::color_to_565(rand.nextU() | (0xFF << 24)));
546
547 int offset = 2 * i * kHalfStrokeWidth + kHalfStrokeWidth;
548 canvas->drawRect(SkRect::MakeXYWH(offset, offset, gWidthHeights[i], gWidthHeights[i]), p);
549 }
550}
551
caryclark70e6d602016-01-30 10:11:21 -0800552DEF_SIMPLE_GM(longwavyline, canvas, 512, 512) {
553 SkPaint p;
554 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400555 p.setStroke(true);
caryclark70e6d602016-01-30 10:11:21 -0800556 p.setStrokeWidth(2);
557
558 SkPath wavy;
559 wavy.moveTo(-10000, 100);
560 for (SkScalar i = -10000; i < 10000; i += 20) {
561 wavy.quadTo(i + 5, 95, i + 10, 100);
562 wavy.quadTo(i + 15, 105, i + 20, 100);
563 }
564 canvas->drawPath(wavy, p);
565}
566
caryclarkd7ea92f2016-03-16 07:34:02 -0700567DEF_SIMPLE_GM(dashtextcaps, canvas, 512, 512) {
568 SkPaint p;
569 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400570 p.setStroke(true);
caryclarkd7ea92f2016-03-16 07:34:02 -0700571 p.setStrokeWidth(10);
572 p.setStrokeCap(SkPaint::kRound_Cap);
caryclark1aaadbd2016-03-17 07:01:49 -0700573 p.setStrokeJoin(SkPaint::kRound_Join);
caryclarkd7ea92f2016-03-16 07:34:02 -0700574 p.setARGB(0xff, 0xbb, 0x00, 0x00);
Mike Reed4de2f1f2019-01-05 16:35:13 -0500575
Mike Kleinea3f0142019-03-20 11:12:10 -0500576 SkFont font(ToolUtils::create_portable_typeface(), 100);
Mike Reed4de2f1f2019-01-05 16:35:13 -0500577
caryclarkd7ea92f2016-03-16 07:34:02 -0700578 const SkScalar intervals[] = { 12, 12 };
reeda4393342016-03-18 11:22:57 -0700579 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
Mike Reed4de2f1f2019-01-05 16:35:13 -0500580 canvas->drawString("Sausages", 10, 90, font, p);
caryclarkd7ea92f2016-03-16 07:34:02 -0700581 canvas->drawLine(8, 120, 456, 120, p);
582}
583
Brian Salomon72f78c32017-12-21 11:56:42 -0500584DEF_SIMPLE_GM(dash_line_zero_off_interval, canvas, 160, 330) {
585 static constexpr SkScalar kIntervals[] = {5.f, 0.f, 2.f, 0.f};
586 SkPaint dashPaint;
587 dashPaint.setPathEffect(SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), 0.f));
588 SkASSERT(dashPaint.getPathEffect());
Mike Reed19630092020-05-18 21:25:44 -0400589 dashPaint.setStroke(true);
Brian Salomon72f78c32017-12-21 11:56:42 -0500590 dashPaint.setStrokeWidth(20.f);
591 static constexpr struct {
592 SkPoint fA, fB;
593 } kLines[] = {{{0.5f, 0.5f}, {30.5f, 0.5f}}, // horizontal
594 {{0.5f, 0.5f}, {0.5f, 30.5f}}, // vertical
595 {{0.5f, 0.5f}, {0.5f, 0.5f}}, // point
596 {{0.5f, 0.5f}, {25.5f, 25.5f}}}; // diagonal
597 SkScalar pad = 5.f + dashPaint.getStrokeWidth();
598 canvas->translate(pad / 2.f, pad / 2.f);
599 canvas->save();
600 SkScalar h = 0.f;
601 for (const auto& line : kLines) {
Brian Osman788b9162020-02-07 10:36:46 -0500602 h = std::max(h, SkScalarAbs(line.fA.fY - line.fB.fY));
Brian Salomon72f78c32017-12-21 11:56:42 -0500603 }
604 for (const auto& line : kLines) {
605 SkScalar w = SkScalarAbs(line.fA.fX - line.fB.fX);
606 for (auto cap : {SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap}) {
607 dashPaint.setStrokeCap(cap);
608 for (auto aa : {false, true}) {
609 dashPaint.setAntiAlias(aa);
610 canvas->drawLine(line.fA, line.fB, dashPaint);
611 canvas->translate(0.f, pad + h);
612 }
613 }
614 canvas->restore();
615 canvas->translate(pad + w, 0.f);
616 canvas->save();
617 }
618}
619
Brian Salomon518fd4d2020-05-08 15:32:28 -0400620DEF_SIMPLE_GM(thin_aa_dash_lines, canvas, 330, 110) {
Brian Salomonc6839122020-05-07 12:43:19 -0400621 SkPaint paint;
Brian Salomon518fd4d2020-05-08 15:32:28 -0400622 static constexpr SkScalar kScale = 100.f;
623 static constexpr SkScalar kIntervals[] = {10/kScale, 5/kScale};
Brian Salomonc6839122020-05-07 12:43:19 -0400624 paint.setPathEffect(SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), 0.f));
625 paint.setAntiAlias(true);
Brian Salomon518fd4d2020-05-08 15:32:28 -0400626 paint.setStrokeWidth(0.25f/kScale);
Brian Salomonc6839122020-05-07 12:43:19 -0400627 // substep moves the subpixel offset every iteration.
Brian Salomon518fd4d2020-05-08 15:32:28 -0400628 static constexpr SkScalar kSubstep = 0.05f/kScale;
Brian Salomonc6839122020-05-07 12:43:19 -0400629 // We will draw a grid of horiz/vertical lines that pass through each other's off intervals.
630 static constexpr SkScalar kStep = kIntervals[0] + kIntervals[1];
Brian Salomon518fd4d2020-05-08 15:32:28 -0400631 canvas->scale(kScale, kScale);
Brian Salomonc6839122020-05-07 12:43:19 -0400632 canvas->translate(kIntervals[1], kIntervals[1]);
Brian Salomon518fd4d2020-05-08 15:32:28 -0400633 for (auto c : {SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap}) {
634 paint.setStrokeCap(c);
635 for (SkScalar x = -.5f*kIntervals[1]; x < 105/kScale; x += (kStep + kSubstep)) {
636 canvas->drawLine({x, 0}, {x, 100/kScale}, paint);
637 canvas->drawLine({0, x}, {100/kScale, x}, paint);
638 }
639 canvas->translate(110/kScale, 0);
Brian Salomonc6839122020-05-07 12:43:19 -0400640 }
641}
642
kcbanner4eb7c232020-11-06 10:05:24 -0500643DEF_SIMPLE_GM(path_effect_empty_result, canvas, 100, 100) {
644 SkPaint p;
645 p.setStroke(true);
646 p.setStrokeWidth(1);
647
648 SkPath path;
649 float r = 70;
650 float l = 70;
651 float t = 70;
652 float b = 70;
653 path.moveTo(l, t);
654 path.lineTo(r, t);
655 path.lineTo(r, b);
656 path.lineTo(l, b);
657 path.close();
658
659 float dashes[] = {2.f, 2.f};
660 p.setPathEffect(SkDashPathEffect::Make(dashes, 2, 0.f));
661
662 canvas->drawPath(path, p);
663}
664
robertphillips9f2251c2014-11-04 13:33:50 -0800665//////////////////////////////////////////////////////////////////////////////
666
halcanary385fe4d2015-08-26 13:07:48 -0700667DEF_GM(return new DashingGM;)
668DEF_GM(return new Dashing2GM;)
669DEF_GM(return new Dashing3GM;)
670DEF_GM(return new Dashing4GM;)
671DEF_GM(return new Dashing5GM(true);)
672DEF_GM(return new Dashing5GM(false);)