blob: 578572cd85e0d6605b44fb147fc868e133f6cd73 [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"
Ben Wagner7fde8e12019-05-01 17:28:53 -040014#include "include/core/SkPath.h"
15#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
108static void make_unit_star(SkPath* path, int n) {
109 SkScalar rad = -SK_ScalarPI / 2;
110 const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000111
reed@google.com21384df2012-05-18 17:59:08 +0000112 path->moveTo(0, -SK_Scalar1);
113 for (int i = 1; i < n; i++) {
114 rad += drad;
Brian Osman4428f2c2019-04-02 10:59:28 -0400115 path->lineTo(SkScalarCos(rad), SkScalarSin(rad));
reed@google.com21384df2012-05-18 17:59:08 +0000116 }
117 path->close();
118}
119
120static void make_path_line(SkPath* path, const SkRect& bounds) {
121 path->moveTo(bounds.left(), bounds.top());
122 path->lineTo(bounds.right(), bounds.bottom());
123}
124
125static void make_path_rect(SkPath* path, const SkRect& bounds) {
126 path->addRect(bounds);
127}
128
129static void make_path_oval(SkPath* path, const SkRect& bounds) {
130 path->addOval(bounds);
131}
132
133static void make_path_star(SkPath* path, const SkRect& bounds) {
134 make_unit_star(path, 5);
135 SkMatrix matrix;
136 matrix.setRectToRect(path->getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
137 path->transform(matrix);
138}
139
140class Dashing2GM : public skiagm::GM {
Hal Canaryfa3305a2019-07-18 12:36:54 -0400141 SkString onShortName() override { return SkString("dashing2"); }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000142
Hal Canaryfa3305a2019-07-18 12:36:54 -0400143 SkISize onISize() override { return {640, 480}; }
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000144
Hal Canaryfa3305a2019-07-18 12:36:54 -0400145 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -0700146 constexpr int gIntervals[] = {
reed@google.com21384df2012-05-18 17:59:08 +0000147 3, // 3 dashes: each count [0] followed by intervals [1..count]
148 2, 10, 10,
149 4, 20, 5, 5, 5,
150 2, 2, 2
151 };
152
153 void (*gProc[])(SkPath*, const SkRect&) = {
154 make_path_line, make_path_rect, make_path_oval, make_path_star,
155 };
rmistry@google.comae933ce2012-08-23 18:19:56 +0000156
reed@google.com21384df2012-05-18 17:59:08 +0000157 SkPaint paint;
158 paint.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400159 paint.setStroke(true);
reed@google.com21384df2012-05-18 17:59:08 +0000160 paint.setStrokeWidth(SkIntToScalar(6));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000161
reed@google.com21384df2012-05-18 17:59:08 +0000162 SkRect bounds = SkRect::MakeWH(SkIntToScalar(120), SkIntToScalar(120));
163 bounds.offset(SkIntToScalar(20), SkIntToScalar(20));
164 SkScalar dx = bounds.width() * 4 / 3;
165 SkScalar dy = bounds.height() * 4 / 3;
166
167 const int* intervals = &gIntervals[1];
168 for (int y = 0; y < gIntervals[0]; ++y) {
169 SkScalar vals[SK_ARRAY_COUNT(gIntervals)]; // more than enough
170 int count = *intervals++;
171 for (int i = 0; i < count; ++i) {
172 vals[i] = SkIntToScalar(*intervals++);
173 }
174 SkScalar phase = vals[0] / 2;
reeda4393342016-03-18 11:22:57 -0700175 paint.setPathEffect(SkDashPathEffect::Make(vals, count, phase));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000176
reed@google.com21384df2012-05-18 17:59:08 +0000177 for (size_t x = 0; x < SK_ARRAY_COUNT(gProc); ++x) {
178 SkPath path;
179 SkRect r = bounds;
180 r.offset(x * dx, y * dy);
181 gProc[x](&path, r);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000182
reed@google.com21384df2012-05-18 17:59:08 +0000183 canvas->drawPath(path, paint);
184 }
185 }
186 }
reed@google.com35a81df2012-05-04 21:49:27 +0000187};
188
189//////////////////////////////////////////////////////////////////////////////
190
robertphillips@google.com629ab542012-11-28 17:18:11 +0000191// Test out the on/off line dashing Chrome if fond of
192class Dashing3GM : public skiagm::GM {
Hal Canaryfa3305a2019-07-18 12:36:54 -0400193 SkString onShortName() override { return SkString("dashing3"); }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000194
Hal Canaryfa3305a2019-07-18 12:36:54 -0400195 SkISize onISize() override { return {640, 480}; }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000196
197 // Draw a 100x100 block of dashed lines. The horizontal ones are BW
198 // while the vertical ones are AA.
skia.committer@gmail.com73b140a2012-12-05 02:01:21 +0000199 void drawDashedLines(SkCanvas* canvas,
200 SkScalar lineLength,
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000201 SkScalar phase,
202 SkScalar dashLength,
203 int strokeWidth,
204 bool circles) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000205 SkPaint p;
206 p.setColor(SK_ColorBLACK);
Mike Reed19630092020-05-18 21:25:44 -0400207 p.setStroke(true);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000208 p.setStrokeWidth(SkIntToScalar(strokeWidth));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000209
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000210 if (circles) {
211 p.setStrokeCap(SkPaint::kRound_Cap);
212 }
213
214 SkScalar intervals[2] = { dashLength, dashLength };
robertphillips@google.com629ab542012-11-28 17:18:11 +0000215
reeda4393342016-03-18 11:22:57 -0700216 p.setPathEffect(SkDashPathEffect::Make(intervals, 2, phase));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000217
218 SkPoint pts[2];
219
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000220 for (int y = 0; y < 100; y += 10*strokeWidth) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000221 pts[0].set(0, SkIntToScalar(y));
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000222 pts[1].set(lineLength, SkIntToScalar(y));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000223
224 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
225 }
226
227 p.setAntiAlias(true);
228
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000229 for (int x = 0; x < 100; x += 14*strokeWidth) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000230 pts[0].set(SkIntToScalar(x), 0);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000231 pts[1].set(SkIntToScalar(x), lineLength);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000232
233 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
234 }
235 }
236
Hal Canaryfa3305a2019-07-18 12:36:54 -0400237 void onDraw(SkCanvas* canvas) override {
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000238 // 1on/1off 1x1 squares with phase of 0 - points fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000239 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000240 canvas->translate(2, 0);
241 this->drawDashedLines(canvas, 100, 0, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000242 canvas->restore();
243
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000244 // 1on/1off 1x1 squares with phase of .5 - rects fastpath (due to partial squares)
robertphillips@google.com629ab542012-11-28 17:18:11 +0000245 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000246 canvas->translate(112, 0);
247 this->drawDashedLines(canvas, 100, SK_ScalarHalf, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000248 canvas->restore();
249
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000250 // 1on/1off 1x1 squares with phase of 1 - points fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000251 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000252 canvas->translate(222, 0);
253 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000254 canvas->restore();
255
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000256 // 1on/1off 1x1 squares with phase of 1 and non-integer length - rects fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000257 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000258 canvas->translate(332, 0);
reed@google.com140d7282013-01-07 20:25:04 +0000259 this->drawDashedLines(canvas, 99.5f, SK_ScalarHalf, SK_Scalar1, 1, false);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000260 canvas->restore();
261
robertphillips@google.com5c4d5582013-01-15 12:53:31 +0000262 // 255on/255off 1x1 squares with phase of 0 - rects fast path
263 canvas->save();
264 canvas->translate(446, 0);
265 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(255), 1, false);
266 canvas->restore();
267
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000268 // 1on/1off 3x3 squares with phase of 0 - points fast path
269 canvas->save();
270 canvas->translate(2, 110);
271 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, false);
272 canvas->restore();
273
274 // 1on/1off 3x3 squares with phase of 1.5 - rects fast path
275 canvas->save();
276 canvas->translate(112, 110);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000277 this->drawDashedLines(canvas, 100, 1.5f, SkIntToScalar(3), 3, false);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000278 canvas->restore();
279
280 // 1on/1off 1x1 circles with phase of 1 - no fast path yet
281 canvas->save();
282 canvas->translate(2, 220);
283 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, true);
284 canvas->restore();
285
286 // 1on/1off 3x3 circles with phase of 1 - no fast path yet
287 canvas->save();
288 canvas->translate(112, 220);
289 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, true);
290 canvas->restore();
291
292 // 1on/1off 1x1 squares with rotation - should break fast path
293 canvas->save();
294 canvas->translate(332+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000295 canvas->rotate(45);
296 canvas->translate(-50, -50);
297
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000298 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000299 canvas->restore();
300
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000301 // 3on/3off 3x1 rects - should use rect fast path regardless of phase
302 for (int phase = 0; phase <= 3; ++phase) {
303 canvas->save();
skia.committer@gmail.com73b140a2012-12-05 02:01:21 +0000304 canvas->translate(SkIntToScalar(phase*110+2),
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000305 SkIntToScalar(330));
306 this->drawDashedLines(canvas, 100, SkIntToScalar(phase), SkIntToScalar(3), 1, false);
307 canvas->restore();
308 }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000309 }
310
311};
312
313//////////////////////////////////////////////////////////////////////////////
314
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000315class Dashing4GM : public skiagm::GM {
Hal Canaryfa3305a2019-07-18 12:36:54 -0400316 SkString onShortName() override { return SkString("dashing4"); }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000317
Hal Canaryfa3305a2019-07-18 12:36:54 -0400318 SkISize onISize() override { return {640, 1100}; }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000319
Hal Canaryfa3305a2019-07-18 12:36:54 -0400320 void onDraw(SkCanvas* canvas) override {
John Stilesdbcf6802020-05-18 10:58:51 -0400321 struct Intervals {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000322 int fOnInterval;
323 int fOffInterval;
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000324 };
325
326 SkPaint paint;
Mike Reed19630092020-05-18 21:25:44 -0400327 paint.setStroke(true);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000328
329 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
Greg Daniel95581bb2017-06-30 10:36:38 -0400330 canvas->translate(SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000331
332 for (int width = 0; width <= 2; ++width) {
John Stilesdbcf6802020-05-18 10:58:51 -0400333 for (const Intervals& data : {Intervals{1, 1},
334 Intervals{4, 2},
335 Intervals{0, 4}}) { // test for zero length on interval
336 for (bool aa : {false, true}) {
337 for (auto cap : {SkPaint::kRound_Cap, SkPaint::kSquare_Cap}) {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000338 int w = width * width * width;
John Stilesdbcf6802020-05-18 10:58:51 -0400339 paint.setAntiAlias(aa);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000340 paint.setStrokeWidth(SkIntToScalar(w));
John Stilesdbcf6802020-05-18 10:58:51 -0400341 paint.setStrokeCap(cap);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000342
343 int scale = w ? w : 1;
344
John Stilesdbcf6802020-05-18 10:58:51 -0400345 drawline(canvas, data.fOnInterval * scale, data.fOffInterval * scale,
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000346 paint);
347 canvas->translate(0, SkIntToScalar(20));
348 }
349 }
350 }
351 }
352
353 for (int aa = 0; aa <= 1; ++aa) {
354 paint.setAntiAlias(SkToBool(aa));
355 paint.setStrokeWidth(8.f);
356 paint.setStrokeCap(SkPaint::kSquare_Cap);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000357 // Single dash element that is cut off at start and end
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000358 drawline(canvas, 32, 16, paint, 20.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000359 canvas->translate(0, SkIntToScalar(20));
360
361 // Two dash elements where each one is cut off at beginning and end respectively
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000362 drawline(canvas, 32, 16, paint, 56.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000363 canvas->translate(0, SkIntToScalar(20));
364
365 // Many dash elements where first and last are cut off at beginning and end respectively
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000366 drawline(canvas, 32, 16, paint, 584.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000367 canvas->translate(0, SkIntToScalar(20));
368
369 // Diagonal dash line where src pnts are not axis aligned (as apposed to being diagonal from
370 // a canvas rotation)
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000371 drawline(canvas, 32, 16, paint, 600.f, 30.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000372 canvas->translate(0, SkIntToScalar(20));
373
374 // Case where only the off interval exists on the line. Thus nothing should be drawn
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000375 drawline(canvas, 32, 16, paint, 8.f, 0.f, 40.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000376 canvas->translate(0, SkIntToScalar(20));
377 }
Greg Daniel5fb30562017-06-29 12:27:48 -0400378
379 // Test overlapping circles.
380 canvas->translate(SkIntToScalar(5), SkIntToScalar(20));
381 paint.setAntiAlias(true);
382 paint.setStrokeCap(SkPaint::kRound_Cap);
383 paint.setColor(0x44000000);
384 paint.setStrokeWidth(40);
385 drawline(canvas, 0, 30, paint);
386
387 canvas->translate(0, SkIntToScalar(50));
388 paint.setStrokeCap(SkPaint::kSquare_Cap);
389 drawline(canvas, 0, 30, paint);
Greg Danielc96f9b52017-12-07 15:00:06 -0500390
391 // Test we draw the cap when the line length is zero.
392 canvas->translate(0, SkIntToScalar(50));
393 paint.setStrokeCap(SkPaint::kRound_Cap);
394 paint.setColor(0xFF000000);
395 paint.setStrokeWidth(11);
396 drawline(canvas, 0, 30, paint, 0);
397
398 canvas->translate(SkIntToScalar(100), 0);
399 drawline(canvas, 1, 30, paint, 0);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000400 }
401};
402
403//////////////////////////////////////////////////////////////////////////////
404
robertphillips9f2251c2014-11-04 13:33:50 -0800405class Dashing5GM : public skiagm::GM {
406public:
407 Dashing5GM(bool doAA) : fDoAA(doAA) {}
reed@google.com35a81df2012-05-04 21:49:27 +0000408
Hal Canaryfa3305a2019-07-18 12:36:54 -0400409private:
mtklein36352bf2015-03-25 18:17:31 -0700410 bool runAsBench() const override { return true; }
mtkleincf5d9c92015-01-23 10:31:45 -0800411
Hal Canaryfa3305a2019-07-18 12:36:54 -0400412 SkString onShortName() override { return SkString(fDoAA ? "dashing5_aa" : "dashing5_bw"); }
robertphillips9f2251c2014-11-04 13:33:50 -0800413
Hal Canaryfa3305a2019-07-18 12:36:54 -0400414 SkISize onISize() override { return {400, 200}; }
robertphillips9f2251c2014-11-04 13:33:50 -0800415
mtklein36352bf2015-03-25 18:17:31 -0700416 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -0700417 constexpr int kOn = 4;
418 constexpr int kOff = 4;
419 constexpr int kIntervalLength = kOn + kOff;
robertphillips9f2251c2014-11-04 13:33:50 -0800420
mtkleindbfd7ab2016-09-01 11:24:54 -0700421 constexpr SkColor gColors[kIntervalLength] = {
robertphillips9f2251c2014-11-04 13:33:50 -0800422 SK_ColorRED,
423 SK_ColorGREEN,
424 SK_ColorBLUE,
425 SK_ColorCYAN,
426 SK_ColorMAGENTA,
427 SK_ColorYELLOW,
428 SK_ColorGRAY,
429 SK_ColorDKGRAY
430 };
431
432 SkPaint paint;
Mike Reed19630092020-05-18 21:25:44 -0400433 paint.setStroke(true);
robertphillips9f2251c2014-11-04 13:33:50 -0800434
435 paint.setAntiAlias(fDoAA);
436
437 SkMatrix rot;
438 rot.setRotate(90);
439 SkASSERT(rot.rectStaysRect());
440
441 canvas->concat(rot);
442
443 int sign; // used to toggle the direction of the lines
444 int phase = 0;
445
446 for (int x = 0; x < 200; x += 10) {
447 paint.setStrokeWidth(SkIntToScalar(phase+1));
448 paint.setColor(gColors[phase]);
449 sign = (x % 20) ? 1 : -1;
halcanary9d524f22016-03-29 09:03:52 -0700450 drawline(canvas, kOn, kOff, paint,
451 SkIntToScalar(x), -sign * SkIntToScalar(10003),
robertphillips9f2251c2014-11-04 13:33:50 -0800452 SkIntToScalar(phase),
453 SkIntToScalar(x), sign * SkIntToScalar(10003));
454 phase = (phase + 1) % kIntervalLength;
455 }
456
457 for (int y = -400; y < 0; y += 10) {
458 paint.setStrokeWidth(SkIntToScalar(phase+1));
459 paint.setColor(gColors[phase]);
460 sign = (y % 20) ? 1 : -1;
halcanary9d524f22016-03-29 09:03:52 -0700461 drawline(canvas, kOn, kOff, paint,
462 -sign * SkIntToScalar(10003), SkIntToScalar(y),
robertphillips9f2251c2014-11-04 13:33:50 -0800463 SkIntToScalar(phase),
464 sign * SkIntToScalar(10003), SkIntToScalar(y));
465 phase = (phase + 1) % kIntervalLength;
466 }
467 }
468
469private:
470 bool fDoAA;
471};
472
reed6dc14aa2016-04-11 07:46:38 -0700473DEF_SIMPLE_GM(longpathdash, canvas, 612, 612) {
caryclarkf97aa742015-12-18 07:03:13 -0800474 SkPath lines;
475 for (int x = 32; x < 256; x += 16) {
476 for (SkScalar a = 0; a < 3.141592f * 2; a += 0.03141592f) {
477 SkPoint pts[2] = {
478 { 256 + (float) sin(a) * x,
479 256 + (float) cos(a) * x },
480 { 256 + (float) sin(a + 3.141592 / 3) * (x + 64),
481 256 + (float) cos(a + 3.141592 / 3) * (x + 64) }
482 };
483 lines.moveTo(pts[0]);
484 for (SkScalar i = 0; i < 1; i += 0.05f) {
485 lines.lineTo(pts[0].fX * (1 - i) + pts[1].fX * i,
486 pts[0].fY * (1 - i) + pts[1].fY * i);
487 }
488 }
489 }
490 SkPaint p;
491 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400492 p.setStroke(true);
caryclarkf97aa742015-12-18 07:03:13 -0800493 p.setStrokeWidth(1);
494 const SkScalar intervals[] = { 1, 1 };
reeda4393342016-03-18 11:22:57 -0700495 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
Ben Wagner63fd7602017-10-09 15:45:33 -0400496
reed6dc14aa2016-04-11 07:46:38 -0700497 canvas->translate(50, 50);
caryclarkf97aa742015-12-18 07:03:13 -0800498 canvas->drawPath(lines, p);
499}
500
caryclark70e6d602016-01-30 10:11:21 -0800501DEF_SIMPLE_GM(longlinedash, canvas, 512, 512) {
502 SkPaint p;
503 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400504 p.setStroke(true);
caryclark70e6d602016-01-30 10:11:21 -0800505 p.setStrokeWidth(80);
506
507 const SkScalar intervals[] = { 2, 2 };
reeda4393342016-03-18 11:22:57 -0700508 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
caryclark70e6d602016-01-30 10:11:21 -0800509 canvas->drawRect(SkRect::MakeXYWH(-10000, 100, 20000, 20), p);
510}
511
512DEF_SIMPLE_GM(longwavyline, canvas, 512, 512) {
513 SkPaint p;
514 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400515 p.setStroke(true);
caryclark70e6d602016-01-30 10:11:21 -0800516 p.setStrokeWidth(2);
517
518 SkPath wavy;
519 wavy.moveTo(-10000, 100);
520 for (SkScalar i = -10000; i < 10000; i += 20) {
521 wavy.quadTo(i + 5, 95, i + 10, 100);
522 wavy.quadTo(i + 15, 105, i + 20, 100);
523 }
524 canvas->drawPath(wavy, p);
525}
526
caryclarkd7ea92f2016-03-16 07:34:02 -0700527DEF_SIMPLE_GM(dashtextcaps, canvas, 512, 512) {
528 SkPaint p;
529 p.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400530 p.setStroke(true);
caryclarkd7ea92f2016-03-16 07:34:02 -0700531 p.setStrokeWidth(10);
532 p.setStrokeCap(SkPaint::kRound_Cap);
caryclark1aaadbd2016-03-17 07:01:49 -0700533 p.setStrokeJoin(SkPaint::kRound_Join);
caryclarkd7ea92f2016-03-16 07:34:02 -0700534 p.setARGB(0xff, 0xbb, 0x00, 0x00);
Mike Reed4de2f1f2019-01-05 16:35:13 -0500535
Mike Kleinea3f0142019-03-20 11:12:10 -0500536 SkFont font(ToolUtils::create_portable_typeface(), 100);
Mike Reed4de2f1f2019-01-05 16:35:13 -0500537
caryclarkd7ea92f2016-03-16 07:34:02 -0700538 const SkScalar intervals[] = { 12, 12 };
reeda4393342016-03-18 11:22:57 -0700539 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
Mike Reed4de2f1f2019-01-05 16:35:13 -0500540 canvas->drawString("Sausages", 10, 90, font, p);
caryclarkd7ea92f2016-03-16 07:34:02 -0700541 canvas->drawLine(8, 120, 456, 120, p);
542}
543
Brian Salomon72f78c32017-12-21 11:56:42 -0500544DEF_SIMPLE_GM(dash_line_zero_off_interval, canvas, 160, 330) {
545 static constexpr SkScalar kIntervals[] = {5.f, 0.f, 2.f, 0.f};
546 SkPaint dashPaint;
547 dashPaint.setPathEffect(SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), 0.f));
548 SkASSERT(dashPaint.getPathEffect());
Mike Reed19630092020-05-18 21:25:44 -0400549 dashPaint.setStroke(true);
Brian Salomon72f78c32017-12-21 11:56:42 -0500550 dashPaint.setStrokeWidth(20.f);
551 static constexpr struct {
552 SkPoint fA, fB;
553 } kLines[] = {{{0.5f, 0.5f}, {30.5f, 0.5f}}, // horizontal
554 {{0.5f, 0.5f}, {0.5f, 30.5f}}, // vertical
555 {{0.5f, 0.5f}, {0.5f, 0.5f}}, // point
556 {{0.5f, 0.5f}, {25.5f, 25.5f}}}; // diagonal
557 SkScalar pad = 5.f + dashPaint.getStrokeWidth();
558 canvas->translate(pad / 2.f, pad / 2.f);
559 canvas->save();
560 SkScalar h = 0.f;
561 for (const auto& line : kLines) {
Brian Osman788b9162020-02-07 10:36:46 -0500562 h = std::max(h, SkScalarAbs(line.fA.fY - line.fB.fY));
Brian Salomon72f78c32017-12-21 11:56:42 -0500563 }
564 for (const auto& line : kLines) {
565 SkScalar w = SkScalarAbs(line.fA.fX - line.fB.fX);
566 for (auto cap : {SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap}) {
567 dashPaint.setStrokeCap(cap);
568 for (auto aa : {false, true}) {
569 dashPaint.setAntiAlias(aa);
570 canvas->drawLine(line.fA, line.fB, dashPaint);
571 canvas->translate(0.f, pad + h);
572 }
573 }
574 canvas->restore();
575 canvas->translate(pad + w, 0.f);
576 canvas->save();
577 }
578}
579
Brian Salomon518fd4d2020-05-08 15:32:28 -0400580DEF_SIMPLE_GM(thin_aa_dash_lines, canvas, 330, 110) {
Brian Salomonc6839122020-05-07 12:43:19 -0400581 SkPaint paint;
Brian Salomon518fd4d2020-05-08 15:32:28 -0400582 static constexpr SkScalar kScale = 100.f;
583 static constexpr SkScalar kIntervals[] = {10/kScale, 5/kScale};
Brian Salomonc6839122020-05-07 12:43:19 -0400584 paint.setPathEffect(SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), 0.f));
585 paint.setAntiAlias(true);
Brian Salomon518fd4d2020-05-08 15:32:28 -0400586 paint.setStrokeWidth(0.25f/kScale);
Brian Salomonc6839122020-05-07 12:43:19 -0400587 // substep moves the subpixel offset every iteration.
Brian Salomon518fd4d2020-05-08 15:32:28 -0400588 static constexpr SkScalar kSubstep = 0.05f/kScale;
Brian Salomonc6839122020-05-07 12:43:19 -0400589 // We will draw a grid of horiz/vertical lines that pass through each other's off intervals.
590 static constexpr SkScalar kStep = kIntervals[0] + kIntervals[1];
Brian Salomon518fd4d2020-05-08 15:32:28 -0400591 canvas->scale(kScale, kScale);
Brian Salomonc6839122020-05-07 12:43:19 -0400592 canvas->translate(kIntervals[1], kIntervals[1]);
Brian Salomon518fd4d2020-05-08 15:32:28 -0400593 for (auto c : {SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap}) {
594 paint.setStrokeCap(c);
595 for (SkScalar x = -.5f*kIntervals[1]; x < 105/kScale; x += (kStep + kSubstep)) {
596 canvas->drawLine({x, 0}, {x, 100/kScale}, paint);
597 canvas->drawLine({0, x}, {100/kScale, x}, paint);
598 }
599 canvas->translate(110/kScale, 0);
Brian Salomonc6839122020-05-07 12:43:19 -0400600 }
601}
602
robertphillips9f2251c2014-11-04 13:33:50 -0800603//////////////////////////////////////////////////////////////////////////////
604
halcanary385fe4d2015-08-26 13:07:48 -0700605DEF_GM(return new DashingGM;)
606DEF_GM(return new Dashing2GM;)
607DEF_GM(return new Dashing3GM;)
608DEF_GM(return new Dashing4GM;)
609DEF_GM(return new Dashing5GM(true);)
610DEF_GM(return new Dashing5GM(false);)