blob: 13dae6d850a185bd1309b91dfe5c040a4dfa34a8 [file] [log] [blame]
bsalomon71c5eee2016-08-19 10:53:13 -07001/*
2 * Copyright 2016 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/SkPaint.h"
12#include "include/core/SkPath.h"
13#include "include/core/SkPathEffect.h"
14#include "include/core/SkRect.h"
15#include "include/core/SkScalar.h"
16#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/effects/SkDashPathEffect.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040018#include "include/private/SkFloatBits.h"
19#include "include/private/SkTArray.h"
20
21#include <functional>
bsalomon71c5eee2016-08-19 10:53:13 -070022
Mike Reed9ded74e2020-05-20 17:01:56 -040023#include "include/effects/SkStrokeAndFillPathEffect.h"
24static void set_strokeandfill(SkPaint* paint) {
25 SkASSERT(paint->getPathEffect() == nullptr);
26 paint->setPathEffect(SkStrokeAndFillPathEffect::Make());
27 paint->setStroke(true);
28}
29
mtkleindbfd7ab2016-09-01 11:24:54 -070030constexpr SkScalar kStarts[] = {0.f, 10.f, 30.f, 45.f, 90.f, 165.f, 180.f, 270.f};
31constexpr SkScalar kSweeps[] = {1.f, 45.f, 90.f, 130.f, 180.f, 184.f, 300.f, 355.f};
32constexpr SkScalar kDiameter = 40.f;
33constexpr SkRect kRect = {0.f, 0.f, kDiameter, kDiameter};
34constexpr int kW = 1000;
35constexpr int kH = 1000;
36constexpr SkScalar kPad = 20.f;
bsalomon71c5eee2016-08-19 10:53:13 -070037
38void draw_arcs(SkCanvas* canvas, std::function<void(SkPaint*)> configureStyle) {
39 // Draws grid of arcs with different start/sweep angles in red and their complement arcs in
40 // blue.
41 auto drawGrid = [canvas, &configureStyle] (SkScalar x, SkScalar y, bool useCenter, bool aa) {
42 SkPaint p0;
43 p0.setColor(SK_ColorRED);
44 p0.setAntiAlias(aa);
45 // Set a reasonable stroke width that configureStyle can override.
46 p0.setStrokeWidth(15.f);
bsalomon71c5eee2016-08-19 10:53:13 -070047 SkPaint p1 = p0;
48 p1.setColor(SK_ColorBLUE);
bsalomon4c547882016-08-19 13:41:28 -070049 // Use alpha so we see magenta on overlap between arc and its complement.
50 p0.setAlpha(100);
51 p1.setAlpha(100);
bsalomon71c5eee2016-08-19 10:53:13 -070052 configureStyle(&p0);
53 configureStyle(&p1);
54
55 canvas->save();
56 canvas->translate(kPad + x, kPad + y);
57 for (auto start : kStarts) {
58 canvas->save();
59 for (auto sweep : kSweeps) {
60 canvas->drawArc(kRect, start, sweep, useCenter, p0);
61 canvas->drawArc(kRect, start, -(360.f - sweep), useCenter, p1);
62 canvas->translate(kRect.width() + kPad, 0.f);
63 }
64 canvas->restore();
65 canvas->translate(0, kRect.height() + kPad);
66 }
67 canvas->restore();
68 };
69 // Draw a grids for combo of enabling/disabling aa and using center.
mtkleindbfd7ab2016-09-01 11:24:54 -070070 constexpr SkScalar kGridW = kW / 2.f;
71 constexpr SkScalar kGridH = kH / 2.f;
bsalomon71c5eee2016-08-19 10:53:13 -070072 drawGrid(0.f , 0.f , false, false);
73 drawGrid(kGridW, 0.f , true , false);
74 drawGrid(0.f , kGridH, false, true );
75 drawGrid(kGridW, kGridH, true , true );
76 // Draw separators between the grids.
77 SkPaint linePaint;
78 linePaint.setAntiAlias(true);
79 linePaint.setColor(SK_ColorBLACK);
80 canvas->drawLine(kGridW, 0.f , kGridW, SkIntToScalar(kH), linePaint);
81 canvas->drawLine(0.f , kGridH, SkIntToScalar(kW), kGridH, linePaint);
82}
83
84#define DEF_ARC_GM(name) DEF_SIMPLE_GM(circular_arcs_##name, canvas, kW, kH)
85
bsalomon4c547882016-08-19 13:41:28 -070086DEF_ARC_GM(fill) {
Mike Reed19630092020-05-18 21:25:44 -040087 auto setFill = [] (SkPaint*p) { p->setStroke(false); };
bsalomon71c5eee2016-08-19 10:53:13 -070088 draw_arcs(canvas, setFill);
89}
90
91DEF_ARC_GM(hairline) {
92 auto setHairline = [] (SkPaint* p) {
Mike Reed19630092020-05-18 21:25:44 -040093 p->setStroke(true);
bsalomon71c5eee2016-08-19 10:53:13 -070094 p->setStrokeWidth(0.f);
95 };
96 draw_arcs(canvas, setHairline);
97}
98
99DEF_ARC_GM(stroke_butt) {
100 auto setStroke = [](SkPaint* p) {
Mike Reed19630092020-05-18 21:25:44 -0400101 p->setStroke(true);
bsalomon71c5eee2016-08-19 10:53:13 -0700102 p->setStrokeCap(SkPaint::kButt_Cap);
103 };
104 draw_arcs(canvas, setStroke);
105}
106
107DEF_ARC_GM(stroke_square) {
108 auto setStroke = [] (SkPaint* p) {
Mike Reed19630092020-05-18 21:25:44 -0400109 p->setStroke(true);
bsalomon71c5eee2016-08-19 10:53:13 -0700110 p->setStrokeCap(SkPaint::kSquare_Cap);
111 };
112 draw_arcs(canvas, setStroke);
113}
114
115DEF_ARC_GM(stroke_round) {
116 auto setStroke = [] (SkPaint* p) {
Mike Reed19630092020-05-18 21:25:44 -0400117 p->setStroke(true);
bsalomon71c5eee2016-08-19 10:53:13 -0700118 p->setStrokeCap(SkPaint::kRound_Cap);
119 };
120 draw_arcs(canvas, setStroke);
121}
bsalomonac1d0ab2016-08-22 10:00:14 -0700122
bsalomon4c261d02016-08-22 13:10:46 -0700123DEF_ARC_GM(stroke_and_fill_butt) {
124 auto setStroke = [] (SkPaint* p) {
Mike Reed9ded74e2020-05-20 17:01:56 -0400125 set_strokeandfill(p);
bsalomon4c261d02016-08-22 13:10:46 -0700126 p->setStrokeCap(SkPaint::kButt_Cap);
127 };
128 draw_arcs(canvas, setStroke);
129}
130
131DEF_ARC_GM(stroke_and_fill_square) {
132 auto setStroke = [] (SkPaint* p) {
Mike Reed9ded74e2020-05-20 17:01:56 -0400133 set_strokeandfill(p);
bsalomon4c261d02016-08-22 13:10:46 -0700134 p->setStrokeCap(SkPaint::kSquare_Cap);
135 };
136 draw_arcs(canvas, setStroke);
137}
138
139DEF_ARC_GM(stroke_and_fill_round) {
bsalomonac1d0ab2016-08-22 10:00:14 -0700140 auto setStroke = [] (SkPaint* p) {
Mike Reed9ded74e2020-05-20 17:01:56 -0400141 set_strokeandfill(p);
bsalomonac1d0ab2016-08-22 10:00:14 -0700142 p->setStrokeCap(SkPaint::kRound_Cap);
143 };
144 draw_arcs(canvas, setStroke);
145}
bsalomon21af9ca2016-08-25 12:29:23 -0700146
147DEF_SIMPLE_GM(circular_arcs_weird, canvas, 1000, 400) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700148 constexpr SkScalar kS = 50;
bsalomon21af9ca2016-08-25 12:29:23 -0700149 struct Arc {
150 SkRect fOval;
151 SkScalar fStart;
152 SkScalar fSweep;
153 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700154 const Arc noDrawArcs[] = {
bsalomon21af9ca2016-08-25 12:29:23 -0700155 // no sweep
156 {SkRect::MakeWH(kS, kS), 0, 0},
157 // empty rect in x
158 {SkRect::MakeWH(-kS, kS), 0, 90},
159 // empty rect in y
160 {SkRect::MakeWH(kS, -kS), 0, 90},
161 // empty rect in x and y
162 {SkRect::MakeWH( 0, 0), 0, 90},
163 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700164 const Arc arcs[] = {
bsalomon21af9ca2016-08-25 12:29:23 -0700165 // large start
166 {SkRect::MakeWH(kS, kS), 810.f, 90.f},
167 // large negative start
168 {SkRect::MakeWH(kS, kS), -810.f, 90.f},
169 // exactly 360 sweep
170 {SkRect::MakeWH(kS, kS), 0.f, 360.f},
171 // exactly -360 sweep
172 {SkRect::MakeWH(kS, kS), 0.f, -360.f},
173 // exactly 540 sweep
174 {SkRect::MakeWH(kS, kS), 0.f, 540.f},
175 // exactly -540 sweep
176 {SkRect::MakeWH(kS, kS), 0.f, -540.f},
177 // generic large sweep and large start
178 {SkRect::MakeWH(kS, kS), 1125.f, 990.f},
179 };
180 SkTArray<SkPaint> paints;
181 // fill
182 paints.push_back();
183 // stroke
Mike Reed19630092020-05-18 21:25:44 -0400184 paints.push_back().setStroke(true);
bsalomon21af9ca2016-08-25 12:29:23 -0700185 paints.back().setStrokeWidth(kS / 6.f);
186 // hairline
Mike Reed19630092020-05-18 21:25:44 -0400187 paints.push_back().setStroke(true);
bsalomon21af9ca2016-08-25 12:29:23 -0700188 paints.back().setStrokeWidth(0.f);
189 // stroke and fill
190 paints.push_back().setStyle(SkPaint::kStrokeAndFill_Style);
191 paints.back().setStrokeWidth(kS / 6.f);
192 // dash effect
Mike Reed19630092020-05-18 21:25:44 -0400193 paints.push_back().setStroke(true);
bsalomon21af9ca2016-08-25 12:29:23 -0700194 paints.back().setStrokeWidth(kS / 6.f);
mtkleindbfd7ab2016-09-01 11:24:54 -0700195 constexpr SkScalar kDashIntervals[] = {kS / 15, 2 * kS / 15};
bsalomon21af9ca2016-08-25 12:29:23 -0700196 paints.back().setPathEffect(SkDashPathEffect::Make(kDashIntervals, 2, 0.f));
197
198 canvas->translate(kPad, kPad);
199 // This loop should draw nothing.
200 for (auto arc : noDrawArcs) {
201 for (auto paint : paints) {
202 paint.setAntiAlias(true);
203 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
204 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
205 }
206 }
207
208 SkPaint linePaint;
209 linePaint.setAntiAlias(true);
210 linePaint.setColor(SK_ColorRED);
211 SkScalar midX = SK_ARRAY_COUNT(arcs) * (kS + kPad) - kPad/2.f;
212 SkScalar height = paints.count() * (kS + kPad);
213 canvas->drawLine(midX, -kPad, midX, height, linePaint);
214
215 for (auto paint : paints) {
216 paint.setAntiAlias(true);
217 canvas->save();
218 for (auto arc : arcs) {
219 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
220 canvas->translate(kS + kPad, 0.f);
221 }
222 for (auto arc : arcs) {
223 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
224 canvas->translate(kS + kPad, 0.f);
225 }
226 canvas->restore();
227 canvas->translate(0, kS + kPad);
228 }
229}
caryclarkf71ab8f2016-08-26 09:54:25 -0700230
231DEF_SIMPLE_GM(onebadarc, canvas, 100, 100) {
232 SkPath path;
233 path.moveTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000)); // 20, 20
234 path.lineTo(SkBits2Float(0x4208918c), SkBits2Float(0x4208918c)); // 34.1421f, 34.1421f
235 path.conicTo(SkBits2Float(0x41a00000), SkBits2Float(0x42412318), // 20, 48.2843f
236 SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c), // 5.85786f, 34.1421f
237 SkBits2Float(0x3f3504f3)); // 0.707107f
238 path.quadTo(SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c), // 5.85786f, 34.1421f
239 SkBits2Float(0x40bb73a2), SkBits2Float(0x4208918c)); // 5.85787f, 34.1421f
240 path.lineTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000)); // 20, 20
241 path.close();
242 SkPaint p0;
243 p0.setColor(SK_ColorRED);
244 p0.setStrokeWidth(15.f);
Mike Reed19630092020-05-18 21:25:44 -0400245 p0.setStroke(true);
caryclarkf71ab8f2016-08-26 09:54:25 -0700246 p0.setAlpha(100);
247 canvas->translate(20, 0);
248 canvas->drawPath(path, p0);
249
250 SkRect kRect = { 60, 0, 100, 40};
251 canvas->drawArc(kRect, 45, 90, true, p0);
252}
Brian Osmane3deee12018-11-20 11:10:15 -0500253
254DEF_SIMPLE_GM(crbug_888453, canvas, 480, 150) {
255 // Two GPU path renderers were using a too-large tolerance when chopping connics to quads.
256 // This manifested as not-very-round circular arcs at certain radii. All the arcs being drawn
257 // here should look like circles.
258 SkPaint fill;
259 fill.setAntiAlias(true);
260 SkPaint hairline = fill;
Mike Reed19630092020-05-18 21:25:44 -0400261 hairline.setStroke(true);
Brian Osmane3deee12018-11-20 11:10:15 -0500262 SkPaint stroke = hairline;
263 stroke.setStrokeWidth(2.0f);
264 int x = 4;
265 int y0 = 25, y1 = 75, y2 = 125;
266 for (int r = 2; r <= 20; ++r) {
267 canvas->drawArc(SkRect::MakeXYWH(x - r, y0 - r, 2 * r, 2 * r), 0, 360, false, fill);
268 canvas->drawArc(SkRect::MakeXYWH(x - r, y1 - r, 2 * r, 2 * r), 0, 360, false, hairline);
269 canvas->drawArc(SkRect::MakeXYWH(x - r, y2 - r, 2 * r, 2 * r), 0, 360, false, stroke);
270 x += 2 * r + 4;
271 }
272}
Brian Salomon3517aa72019-12-11 08:16:22 -0500273
274DEF_SIMPLE_GM(circular_arc_stroke_matrix, canvas, 820, 1090) {
275 static constexpr SkScalar kRadius = 40.f;
276 static constexpr SkScalar kStrokeWidth = 5.f;
277 static constexpr SkScalar kStart = 89.f;
278 static constexpr SkScalar kSweep = 180.f/SK_ScalarPI; // one radian
279
280 SkTArray<SkMatrix> matrices;
281 matrices.push_back().setRotate(kRadius, kRadius, 45.f);
282 matrices.push_back(SkMatrix::I());
283 matrices.push_back().setAll(-1, 0, 2*kRadius,
284 0, 1, 0,
285 0, 0, 1);
286 matrices.push_back().setAll( 1, 0, 0,
287 0, -1, 2*kRadius,
288 0, 0, 1);
289 matrices.push_back().setAll( 1, 0, 0,
290 0, -1, 2*kRadius,
291 0, 0, 1);
292 matrices.push_back().setAll( 0, -1, 2*kRadius,
293 -1, 0, 2*kRadius,
294 0, 0, 1);
295 matrices.push_back().setAll( 0, -1, 2*kRadius,
296 1, 0, 0,
297 0, 0, 1);
298 matrices.push_back().setAll( 0, 1, 0,
299 1, 0, 0,
300 0, 0, 1);
301 matrices.push_back().setAll( 0, 1, 0,
302 -1, 0, 2*kRadius,
303 0, 0, 1);
304 int baseMatrixCnt = matrices.count();
305
306
307 SkMatrix tinyCW;
308 tinyCW.setRotate(0.001f, kRadius, kRadius);
309 for (int i = 0; i < baseMatrixCnt; ++i) {
310 matrices.push_back().setConcat(matrices[i], tinyCW);
311 }
312 SkMatrix tinyCCW;
313 tinyCCW.setRotate(-0.001f, kRadius, kRadius);
314 for (int i = 0; i < baseMatrixCnt; ++i) {
315 matrices.push_back().setConcat(matrices[i], tinyCCW);
316 }
317 SkMatrix cw45;
318 cw45.setRotate(45.f, kRadius, kRadius);
319 for (int i = 0; i < baseMatrixCnt; ++i) {
320 matrices.push_back().setConcat(matrices[i], cw45);
321 }
322
323 int x = 0;
324 int y = 0;
325 static constexpr SkScalar kPad = 2*kStrokeWidth;
326 canvas->translate(kPad, kPad);
327 auto bounds = SkRect::MakeWH(2*kRadius, 2*kRadius);
328 for (auto cap : {SkPaint::kRound_Cap, SkPaint::kButt_Cap, SkPaint::kSquare_Cap}) {
329 for (const auto& m : matrices) {
330 SkPaint paint;
331 paint.setStrokeCap(cap);
332 paint.setAntiAlias(true);
Mike Reed19630092020-05-18 21:25:44 -0400333 paint.setStroke(true);
Brian Salomon3517aa72019-12-11 08:16:22 -0500334 paint.setStrokeWidth(kStrokeWidth);
335 canvas->save();
336 canvas->translate(x * (2*kRadius + kPad), y * (2*kRadius + kPad));
337 canvas->concat(m);
338 paint.setColor(SK_ColorRED);
339 paint.setAlpha(0x80);
340 canvas->drawArc(bounds, kStart, kSweep, false, paint);
341 paint.setColor(SK_ColorBLUE);
342 paint.setAlpha(0x80);
343 canvas->drawArc(bounds, kStart, kSweep - 360.f, false, paint);
344 canvas->restore();
345 ++x;
346 if (x == baseMatrixCnt) {
347 x = 0;
348 ++y;
349 }
350 }
351 }
352}