blob: 6677f94d3f0baef63c7125fc7b164ba0f4d7926f [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));
57 paint.setStyle(SkPaint::kStroke_Style);
58 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 {
reed@google.com35a81df2012-05-04 21:49:27 +000064public:
65 DashingGM() {}
66
67protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000068
reed@google.com35a81df2012-05-04 21:49:27 +000069 SkString onShortName() {
70 return SkString("dashing");
71 }
72
egdanielc00389e2015-10-05 08:11:49 -070073 SkISize onISize() { return SkISize::Make(640, 340); }
reed@google.com35a81df2012-05-04 21:49:27 +000074
75 virtual void onDraw(SkCanvas* canvas) {
mtkleindbfd7ab2016-09-01 11:24:54 -070076 constexpr struct {
reed@google.com35a81df2012-05-04 21:49:27 +000077 int fOnInterval;
78 int fOffInterval;
79 } gData[] = {
80 { 1, 1 },
81 { 4, 1 },
82 };
rmistry@google.comae933ce2012-08-23 18:19:56 +000083
reed@google.com35a81df2012-05-04 21:49:27 +000084 SkPaint paint;
85 paint.setStyle(SkPaint::kStroke_Style);
86
87 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
88 canvas->translate(0, SK_ScalarHalf);
reed@google.com35a81df2012-05-04 21:49:27 +000089 for (int width = 0; width <= 2; ++width) {
90 for (size_t data = 0; data < SK_ARRAY_COUNT(gData); ++data) {
91 for (int aa = 0; aa <= 1; ++aa) {
92 int w = width * width * width;
93 paint.setAntiAlias(SkToBool(aa));
94 paint.setStrokeWidth(SkIntToScalar(w));
rmistry@google.comae933ce2012-08-23 18:19:56 +000095
reed@google.com35a81df2012-05-04 21:49:27 +000096 int scale = w ? w : 1;
97
98 drawline(canvas, gData[data].fOnInterval * scale,
99 gData[data].fOffInterval * scale,
100 paint);
101 canvas->translate(0, SkIntToScalar(20));
102 }
103 }
104 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000105
reed@google.comde1837b2012-05-21 16:47:43 +0000106 show_giant_dash(canvas);
egdaniel21402e32014-11-05 05:02:27 -0800107 canvas->translate(0, SkIntToScalar(20));
108 show_zero_len_dash(canvas);
egdanielc00389e2015-10-05 08:11:49 -0700109 canvas->translate(0, SkIntToScalar(20));
110 // Draw 0 on, 0 off dashed line
111 paint.setStrokeWidth(SkIntToScalar(8));
112 drawline(canvas, 0, 0, paint);
reed@google.com35a81df2012-05-04 21:49:27 +0000113 }
reed@google.com21384df2012-05-18 17:59:08 +0000114};
reed@google.com35a81df2012-05-04 21:49:27 +0000115
reed@google.com21384df2012-05-18 17:59:08 +0000116///////////////////////////////////////////////////////////////////////////////
117
118static void make_unit_star(SkPath* path, int n) {
119 SkScalar rad = -SK_ScalarPI / 2;
120 const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
rmistry@google.comae933ce2012-08-23 18:19:56 +0000121
reed@google.com21384df2012-05-18 17:59:08 +0000122 path->moveTo(0, -SK_Scalar1);
123 for (int i = 1; i < n; i++) {
124 rad += drad;
Brian Osman4428f2c2019-04-02 10:59:28 -0400125 path->lineTo(SkScalarCos(rad), SkScalarSin(rad));
reed@google.com21384df2012-05-18 17:59:08 +0000126 }
127 path->close();
128}
129
130static void make_path_line(SkPath* path, const SkRect& bounds) {
131 path->moveTo(bounds.left(), bounds.top());
132 path->lineTo(bounds.right(), bounds.bottom());
133}
134
135static void make_path_rect(SkPath* path, const SkRect& bounds) {
136 path->addRect(bounds);
137}
138
139static void make_path_oval(SkPath* path, const SkRect& bounds) {
140 path->addOval(bounds);
141}
142
143static void make_path_star(SkPath* path, const SkRect& bounds) {
144 make_unit_star(path, 5);
145 SkMatrix matrix;
146 matrix.setRectToRect(path->getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
147 path->transform(matrix);
148}
149
150class Dashing2GM : public skiagm::GM {
151public:
152 Dashing2GM() {}
rmistry@google.comae933ce2012-08-23 18:19:56 +0000153
reed@google.com21384df2012-05-18 17:59:08 +0000154protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000155
reed@google.com21384df2012-05-18 17:59:08 +0000156 SkString onShortName() {
157 return SkString("dashing2");
158 }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000159
tfarinaf5393182014-06-09 23:59:03 -0700160 SkISize onISize() { return SkISize::Make(640, 480); }
rmistry@google.comae933ce2012-08-23 18:19:56 +0000161
reed@google.com21384df2012-05-18 17:59:08 +0000162 virtual void onDraw(SkCanvas* canvas) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700163 constexpr int gIntervals[] = {
reed@google.com21384df2012-05-18 17:59:08 +0000164 3, // 3 dashes: each count [0] followed by intervals [1..count]
165 2, 10, 10,
166 4, 20, 5, 5, 5,
167 2, 2, 2
168 };
169
170 void (*gProc[])(SkPath*, const SkRect&) = {
171 make_path_line, make_path_rect, make_path_oval, make_path_star,
172 };
rmistry@google.comae933ce2012-08-23 18:19:56 +0000173
reed@google.com21384df2012-05-18 17:59:08 +0000174 SkPaint paint;
175 paint.setAntiAlias(true);
176 paint.setStyle(SkPaint::kStroke_Style);
177 paint.setStrokeWidth(SkIntToScalar(6));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000178
reed@google.com21384df2012-05-18 17:59:08 +0000179 SkRect bounds = SkRect::MakeWH(SkIntToScalar(120), SkIntToScalar(120));
180 bounds.offset(SkIntToScalar(20), SkIntToScalar(20));
181 SkScalar dx = bounds.width() * 4 / 3;
182 SkScalar dy = bounds.height() * 4 / 3;
183
184 const int* intervals = &gIntervals[1];
185 for (int y = 0; y < gIntervals[0]; ++y) {
186 SkScalar vals[SK_ARRAY_COUNT(gIntervals)]; // more than enough
187 int count = *intervals++;
188 for (int i = 0; i < count; ++i) {
189 vals[i] = SkIntToScalar(*intervals++);
190 }
191 SkScalar phase = vals[0] / 2;
reeda4393342016-03-18 11:22:57 -0700192 paint.setPathEffect(SkDashPathEffect::Make(vals, count, phase));
rmistry@google.comae933ce2012-08-23 18:19:56 +0000193
reed@google.com21384df2012-05-18 17:59:08 +0000194 for (size_t x = 0; x < SK_ARRAY_COUNT(gProc); ++x) {
195 SkPath path;
196 SkRect r = bounds;
197 r.offset(x * dx, y * dy);
198 gProc[x](&path, r);
rmistry@google.comae933ce2012-08-23 18:19:56 +0000199
reed@google.com21384df2012-05-18 17:59:08 +0000200 canvas->drawPath(path, paint);
201 }
202 }
203 }
reed@google.com35a81df2012-05-04 21:49:27 +0000204};
205
206//////////////////////////////////////////////////////////////////////////////
207
robertphillips@google.com629ab542012-11-28 17:18:11 +0000208// Test out the on/off line dashing Chrome if fond of
209class Dashing3GM : public skiagm::GM {
210public:
211 Dashing3GM() {}
212
213protected:
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +0000214
robertphillips@google.com629ab542012-11-28 17:18:11 +0000215 SkString onShortName() {
216 return SkString("dashing3");
217 }
218
tfarinaf5393182014-06-09 23:59:03 -0700219 SkISize onISize() { return SkISize::Make(640, 480); }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000220
221 // Draw a 100x100 block of dashed lines. The horizontal ones are BW
222 // while the vertical ones are AA.
skia.committer@gmail.com73b140a2012-12-05 02:01:21 +0000223 void drawDashedLines(SkCanvas* canvas,
224 SkScalar lineLength,
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000225 SkScalar phase,
226 SkScalar dashLength,
227 int strokeWidth,
228 bool circles) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000229 SkPaint p;
230 p.setColor(SK_ColorBLACK);
231 p.setStyle(SkPaint::kStroke_Style);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000232 p.setStrokeWidth(SkIntToScalar(strokeWidth));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000233
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000234 if (circles) {
235 p.setStrokeCap(SkPaint::kRound_Cap);
236 }
237
238 SkScalar intervals[2] = { dashLength, dashLength };
robertphillips@google.com629ab542012-11-28 17:18:11 +0000239
reeda4393342016-03-18 11:22:57 -0700240 p.setPathEffect(SkDashPathEffect::Make(intervals, 2, phase));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000241
242 SkPoint pts[2];
243
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000244 for (int y = 0; y < 100; y += 10*strokeWidth) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000245 pts[0].set(0, SkIntToScalar(y));
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000246 pts[1].set(lineLength, SkIntToScalar(y));
robertphillips@google.com629ab542012-11-28 17:18:11 +0000247
248 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
249 }
250
251 p.setAntiAlias(true);
252
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000253 for (int x = 0; x < 100; x += 14*strokeWidth) {
robertphillips@google.com629ab542012-11-28 17:18:11 +0000254 pts[0].set(SkIntToScalar(x), 0);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000255 pts[1].set(SkIntToScalar(x), lineLength);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000256
257 canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
258 }
259 }
260
261 virtual void onDraw(SkCanvas* canvas) {
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000262 // 1on/1off 1x1 squares with phase of 0 - points fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000263 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000264 canvas->translate(2, 0);
265 this->drawDashedLines(canvas, 100, 0, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000266 canvas->restore();
267
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000268 // 1on/1off 1x1 squares with phase of .5 - rects fastpath (due to partial squares)
robertphillips@google.com629ab542012-11-28 17:18:11 +0000269 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000270 canvas->translate(112, 0);
271 this->drawDashedLines(canvas, 100, SK_ScalarHalf, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000272 canvas->restore();
273
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000274 // 1on/1off 1x1 squares with phase of 1 - points fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000275 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000276 canvas->translate(222, 0);
277 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000278 canvas->restore();
279
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000280 // 1on/1off 1x1 squares with phase of 1 and non-integer length - rects fastpath
robertphillips@google.com629ab542012-11-28 17:18:11 +0000281 canvas->save();
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000282 canvas->translate(332, 0);
reed@google.com140d7282013-01-07 20:25:04 +0000283 this->drawDashedLines(canvas, 99.5f, SK_ScalarHalf, SK_Scalar1, 1, false);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000284 canvas->restore();
285
robertphillips@google.com5c4d5582013-01-15 12:53:31 +0000286 // 255on/255off 1x1 squares with phase of 0 - rects fast path
287 canvas->save();
288 canvas->translate(446, 0);
289 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(255), 1, false);
290 canvas->restore();
291
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000292 // 1on/1off 3x3 squares with phase of 0 - points fast path
293 canvas->save();
294 canvas->translate(2, 110);
295 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, false);
296 canvas->restore();
297
298 // 1on/1off 3x3 squares with phase of 1.5 - rects fast path
299 canvas->save();
300 canvas->translate(112, 110);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000301 this->drawDashedLines(canvas, 100, 1.5f, SkIntToScalar(3), 3, false);
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000302 canvas->restore();
303
304 // 1on/1off 1x1 circles with phase of 1 - no fast path yet
305 canvas->save();
306 canvas->translate(2, 220);
307 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, true);
308 canvas->restore();
309
310 // 1on/1off 3x3 circles with phase of 1 - no fast path yet
311 canvas->save();
312 canvas->translate(112, 220);
313 this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, true);
314 canvas->restore();
315
316 // 1on/1off 1x1 squares with rotation - should break fast path
317 canvas->save();
318 canvas->translate(332+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000319 canvas->rotate(45);
320 canvas->translate(-50, -50);
321
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000322 this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
robertphillips@google.com629ab542012-11-28 17:18:11 +0000323 canvas->restore();
324
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000325 // 3on/3off 3x1 rects - should use rect fast path regardless of phase
326 for (int phase = 0; phase <= 3; ++phase) {
327 canvas->save();
skia.committer@gmail.com73b140a2012-12-05 02:01:21 +0000328 canvas->translate(SkIntToScalar(phase*110+2),
robertphillips@google.com8c685c52012-12-04 20:34:11 +0000329 SkIntToScalar(330));
330 this->drawDashedLines(canvas, 100, SkIntToScalar(phase), SkIntToScalar(3), 1, false);
331 canvas->restore();
332 }
robertphillips@google.com629ab542012-11-28 17:18:11 +0000333 }
334
335};
336
337//////////////////////////////////////////////////////////////////////////////
338
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000339class Dashing4GM : public skiagm::GM {
340public:
341 Dashing4GM() {}
342
343protected:
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000344
345 SkString onShortName() {
346 return SkString("dashing4");
347 }
348
Greg Danielc96f9b52017-12-07 15:00:06 -0500349 SkISize onISize() { return SkISize::Make(640, 1100); }
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000350
351 virtual void onDraw(SkCanvas* canvas) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700352 constexpr struct {
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000353 int fOnInterval;
354 int fOffInterval;
355 } gData[] = {
356 { 1, 1 },
357 { 4, 2 },
358 { 0, 4 }, // test for zero length on interval
359 };
360
361 SkPaint paint;
362 paint.setStyle(SkPaint::kStroke_Style);
363
364 canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
Greg Daniel95581bb2017-06-30 10:36:38 -0400365 canvas->translate(SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000366
367 for (int width = 0; width <= 2; ++width) {
368 for (size_t data = 0; data < SK_ARRAY_COUNT(gData); ++data) {
369 for (int aa = 0; aa <= 1; ++aa) {
370 for (int cap = 0; cap <= 1; ++cap) {
371 int w = width * width * width;
372 paint.setAntiAlias(SkToBool(aa));
373 paint.setStrokeWidth(SkIntToScalar(w));
374
375 SkToBool(cap) ? paint.setStrokeCap(SkPaint::kSquare_Cap)
376 : paint.setStrokeCap(SkPaint::kRound_Cap);
377
378 int scale = w ? w : 1;
379
380 drawline(canvas, gData[data].fOnInterval * scale,
381 gData[data].fOffInterval * scale,
382 paint);
383 canvas->translate(0, SkIntToScalar(20));
384 }
385 }
386 }
387 }
388
389 for (int aa = 0; aa <= 1; ++aa) {
390 paint.setAntiAlias(SkToBool(aa));
391 paint.setStrokeWidth(8.f);
392 paint.setStrokeCap(SkPaint::kSquare_Cap);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000393 // Single dash element that is cut off at start and end
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000394 drawline(canvas, 32, 16, paint, 20.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000395 canvas->translate(0, SkIntToScalar(20));
396
397 // Two dash elements where each one is cut off at beginning and end respectively
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000398 drawline(canvas, 32, 16, paint, 56.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000399 canvas->translate(0, SkIntToScalar(20));
400
401 // Many dash elements where first and last are cut off at beginning and end respectively
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000402 drawline(canvas, 32, 16, paint, 584.f, 0, 5.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000403 canvas->translate(0, SkIntToScalar(20));
404
405 // Diagonal dash line where src pnts are not axis aligned (as apposed to being diagonal from
406 // a canvas rotation)
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000407 drawline(canvas, 32, 16, paint, 600.f, 30.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000408 canvas->translate(0, SkIntToScalar(20));
409
410 // Case where only the off interval exists on the line. Thus nothing should be drawn
commit-bot@chromium.org71db8822014-05-19 14:59:04 +0000411 drawline(canvas, 32, 16, paint, 8.f, 0.f, 40.f);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000412 canvas->translate(0, SkIntToScalar(20));
413 }
Greg Daniel5fb30562017-06-29 12:27:48 -0400414
415 // Test overlapping circles.
416 canvas->translate(SkIntToScalar(5), SkIntToScalar(20));
417 paint.setAntiAlias(true);
418 paint.setStrokeCap(SkPaint::kRound_Cap);
419 paint.setColor(0x44000000);
420 paint.setStrokeWidth(40);
421 drawline(canvas, 0, 30, paint);
422
423 canvas->translate(0, SkIntToScalar(50));
424 paint.setStrokeCap(SkPaint::kSquare_Cap);
425 drawline(canvas, 0, 30, paint);
Greg Danielc96f9b52017-12-07 15:00:06 -0500426
427 // Test we draw the cap when the line length is zero.
428 canvas->translate(0, SkIntToScalar(50));
429 paint.setStrokeCap(SkPaint::kRound_Cap);
430 paint.setColor(0xFF000000);
431 paint.setStrokeWidth(11);
432 drawline(canvas, 0, 30, paint, 0);
433
434 canvas->translate(SkIntToScalar(100), 0);
435 drawline(canvas, 1, 30, paint, 0);
commit-bot@chromium.org628ed0b2014-05-19 14:32:49 +0000436 }
437};
438
439//////////////////////////////////////////////////////////////////////////////
440
robertphillips9f2251c2014-11-04 13:33:50 -0800441class Dashing5GM : public skiagm::GM {
442public:
443 Dashing5GM(bool doAA) : fDoAA(doAA) {}
reed@google.com35a81df2012-05-04 21:49:27 +0000444
robertphillips9f2251c2014-11-04 13:33:50 -0800445protected:
robertphillips9f2251c2014-11-04 13:33:50 -0800446
mtklein36352bf2015-03-25 18:17:31 -0700447 bool runAsBench() const override { return true; }
mtkleincf5d9c92015-01-23 10:31:45 -0800448
mtklein36352bf2015-03-25 18:17:31 -0700449 SkString onShortName() override {
robertphillips9f2251c2014-11-04 13:33:50 -0800450 if (fDoAA) {
451 return SkString("dashing5_aa");
452 } else {
453 return SkString("dashing5_bw");
454 }
455 }
456
mtklein36352bf2015-03-25 18:17:31 -0700457 SkISize onISize() override { return SkISize::Make(400, 200); }
robertphillips9f2251c2014-11-04 13:33:50 -0800458
mtklein36352bf2015-03-25 18:17:31 -0700459 void onDraw(SkCanvas* canvas) override {
mtkleindbfd7ab2016-09-01 11:24:54 -0700460 constexpr int kOn = 4;
461 constexpr int kOff = 4;
462 constexpr int kIntervalLength = kOn + kOff;
robertphillips9f2251c2014-11-04 13:33:50 -0800463
mtkleindbfd7ab2016-09-01 11:24:54 -0700464 constexpr SkColor gColors[kIntervalLength] = {
robertphillips9f2251c2014-11-04 13:33:50 -0800465 SK_ColorRED,
466 SK_ColorGREEN,
467 SK_ColorBLUE,
468 SK_ColorCYAN,
469 SK_ColorMAGENTA,
470 SK_ColorYELLOW,
471 SK_ColorGRAY,
472 SK_ColorDKGRAY
473 };
474
475 SkPaint paint;
476 paint.setStyle(SkPaint::kStroke_Style);
477
478 paint.setAntiAlias(fDoAA);
479
480 SkMatrix rot;
481 rot.setRotate(90);
482 SkASSERT(rot.rectStaysRect());
483
484 canvas->concat(rot);
485
486 int sign; // used to toggle the direction of the lines
487 int phase = 0;
488
489 for (int x = 0; x < 200; x += 10) {
490 paint.setStrokeWidth(SkIntToScalar(phase+1));
491 paint.setColor(gColors[phase]);
492 sign = (x % 20) ? 1 : -1;
halcanary9d524f22016-03-29 09:03:52 -0700493 drawline(canvas, kOn, kOff, paint,
494 SkIntToScalar(x), -sign * SkIntToScalar(10003),
robertphillips9f2251c2014-11-04 13:33:50 -0800495 SkIntToScalar(phase),
496 SkIntToScalar(x), sign * SkIntToScalar(10003));
497 phase = (phase + 1) % kIntervalLength;
498 }
499
500 for (int y = -400; y < 0; y += 10) {
501 paint.setStrokeWidth(SkIntToScalar(phase+1));
502 paint.setColor(gColors[phase]);
503 sign = (y % 20) ? 1 : -1;
halcanary9d524f22016-03-29 09:03:52 -0700504 drawline(canvas, kOn, kOff, paint,
505 -sign * SkIntToScalar(10003), SkIntToScalar(y),
robertphillips9f2251c2014-11-04 13:33:50 -0800506 SkIntToScalar(phase),
507 sign * SkIntToScalar(10003), SkIntToScalar(y));
508 phase = (phase + 1) % kIntervalLength;
509 }
510 }
511
512private:
513 bool fDoAA;
514};
515
reed6dc14aa2016-04-11 07:46:38 -0700516DEF_SIMPLE_GM(longpathdash, canvas, 612, 612) {
caryclarkf97aa742015-12-18 07:03:13 -0800517 SkPath lines;
518 for (int x = 32; x < 256; x += 16) {
519 for (SkScalar a = 0; a < 3.141592f * 2; a += 0.03141592f) {
520 SkPoint pts[2] = {
521 { 256 + (float) sin(a) * x,
522 256 + (float) cos(a) * x },
523 { 256 + (float) sin(a + 3.141592 / 3) * (x + 64),
524 256 + (float) cos(a + 3.141592 / 3) * (x + 64) }
525 };
526 lines.moveTo(pts[0]);
527 for (SkScalar i = 0; i < 1; i += 0.05f) {
528 lines.lineTo(pts[0].fX * (1 - i) + pts[1].fX * i,
529 pts[0].fY * (1 - i) + pts[1].fY * i);
530 }
531 }
532 }
533 SkPaint p;
534 p.setAntiAlias(true);
535 p.setStyle(SkPaint::kStroke_Style);
536 p.setStrokeWidth(1);
537 const SkScalar intervals[] = { 1, 1 };
reeda4393342016-03-18 11:22:57 -0700538 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
Ben Wagner63fd7602017-10-09 15:45:33 -0400539
reed6dc14aa2016-04-11 07:46:38 -0700540 canvas->translate(50, 50);
caryclarkf97aa742015-12-18 07:03:13 -0800541 canvas->drawPath(lines, p);
542}
543
caryclark70e6d602016-01-30 10:11:21 -0800544DEF_SIMPLE_GM(longlinedash, canvas, 512, 512) {
545 SkPaint p;
546 p.setAntiAlias(true);
547 p.setStyle(SkPaint::kStroke_Style);
548 p.setStrokeWidth(80);
549
550 const SkScalar intervals[] = { 2, 2 };
reeda4393342016-03-18 11:22:57 -0700551 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
caryclark70e6d602016-01-30 10:11:21 -0800552 canvas->drawRect(SkRect::MakeXYWH(-10000, 100, 20000, 20), p);
553}
554
555DEF_SIMPLE_GM(longwavyline, canvas, 512, 512) {
556 SkPaint p;
557 p.setAntiAlias(true);
558 p.setStyle(SkPaint::kStroke_Style);
559 p.setStrokeWidth(2);
560
561 SkPath wavy;
562 wavy.moveTo(-10000, 100);
563 for (SkScalar i = -10000; i < 10000; i += 20) {
564 wavy.quadTo(i + 5, 95, i + 10, 100);
565 wavy.quadTo(i + 15, 105, i + 20, 100);
566 }
567 canvas->drawPath(wavy, p);
568}
569
caryclarkd7ea92f2016-03-16 07:34:02 -0700570DEF_SIMPLE_GM(dashtextcaps, canvas, 512, 512) {
571 SkPaint p;
572 p.setAntiAlias(true);
573 p.setStyle(SkPaint::kStroke_Style);
574 p.setStrokeWidth(10);
575 p.setStrokeCap(SkPaint::kRound_Cap);
caryclark1aaadbd2016-03-17 07:01:49 -0700576 p.setStrokeJoin(SkPaint::kRound_Join);
caryclarkd7ea92f2016-03-16 07:34:02 -0700577 p.setARGB(0xff, 0xbb, 0x00, 0x00);
Mike Reed4de2f1f2019-01-05 16:35:13 -0500578
Mike Kleinea3f0142019-03-20 11:12:10 -0500579 SkFont font(ToolUtils::create_portable_typeface(), 100);
Mike Reed4de2f1f2019-01-05 16:35:13 -0500580
caryclarkd7ea92f2016-03-16 07:34:02 -0700581 const SkScalar intervals[] = { 12, 12 };
reeda4393342016-03-18 11:22:57 -0700582 p.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
Mike Reed4de2f1f2019-01-05 16:35:13 -0500583 canvas->drawString("Sausages", 10, 90, font, p);
caryclarkd7ea92f2016-03-16 07:34:02 -0700584 canvas->drawLine(8, 120, 456, 120, p);
585}
586
Brian Salomon72f78c32017-12-21 11:56:42 -0500587DEF_SIMPLE_GM(dash_line_zero_off_interval, canvas, 160, 330) {
588 static constexpr SkScalar kIntervals[] = {5.f, 0.f, 2.f, 0.f};
589 SkPaint dashPaint;
590 dashPaint.setPathEffect(SkDashPathEffect::Make(kIntervals, SK_ARRAY_COUNT(kIntervals), 0.f));
591 SkASSERT(dashPaint.getPathEffect());
592 dashPaint.setStyle(SkPaint::kStroke_Style);
593 dashPaint.setStrokeWidth(20.f);
594 static constexpr struct {
595 SkPoint fA, fB;
596 } kLines[] = {{{0.5f, 0.5f}, {30.5f, 0.5f}}, // horizontal
597 {{0.5f, 0.5f}, {0.5f, 30.5f}}, // vertical
598 {{0.5f, 0.5f}, {0.5f, 0.5f}}, // point
599 {{0.5f, 0.5f}, {25.5f, 25.5f}}}; // diagonal
600 SkScalar pad = 5.f + dashPaint.getStrokeWidth();
601 canvas->translate(pad / 2.f, pad / 2.f);
602 canvas->save();
603 SkScalar h = 0.f;
604 for (const auto& line : kLines) {
605 h = SkTMax(h, SkScalarAbs(line.fA.fY - line.fB.fY));
606 }
607 for (const auto& line : kLines) {
608 SkScalar w = SkScalarAbs(line.fA.fX - line.fB.fX);
609 for (auto cap : {SkPaint::kButt_Cap, SkPaint::kSquare_Cap, SkPaint::kRound_Cap}) {
610 dashPaint.setStrokeCap(cap);
611 for (auto aa : {false, true}) {
612 dashPaint.setAntiAlias(aa);
613 canvas->drawLine(line.fA, line.fB, dashPaint);
614 canvas->translate(0.f, pad + h);
615 }
616 }
617 canvas->restore();
618 canvas->translate(pad + w, 0.f);
619 canvas->save();
620 }
621}
622
robertphillips9f2251c2014-11-04 13:33:50 -0800623//////////////////////////////////////////////////////////////////////////////
624
halcanary385fe4d2015-08-26 13:07:48 -0700625DEF_GM(return new DashingGM;)
626DEF_GM(return new Dashing2GM;)
627DEF_GM(return new Dashing3GM;)
628DEF_GM(return new Dashing4GM;)
629DEF_GM(return new Dashing5GM(true);)
630DEF_GM(return new Dashing5GM(false);)