Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
circulararcs.cpp
Go to the documentation of this file.
1/*
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
8#include "gm/gm.h"
14#include "include/core/SkRect.h"
20
21#include <functional>
22
23using namespace skia_private;
24
25constexpr SkScalar kStarts[] = {0.f, 10.f, 30.f, 45.f, 90.f, 165.f, 180.f, 270.f};
26constexpr SkScalar kSweeps[] = {1.f, 45.f, 90.f, 130.f, 180.f, 184.f, 300.f, 355.f};
27constexpr SkScalar kDiameter = 40.f;
28constexpr SkRect kRect = {0.f, 0.f, kDiameter, kDiameter};
29constexpr int kW = 1000;
30constexpr int kH = 1000;
31
32void draw_arcs(SkCanvas* canvas, std::function<void(SkPaint*)> configureStyle) {
33 // Draws grid of arcs with different start/sweep angles in red and their complement arcs in
34 // blue.
35 auto drawGrid = [canvas, &configureStyle] (SkScalar x, SkScalar y, bool useCenter, bool aa) {
36 constexpr SkScalar kPad = 20.f;
37 SkPaint p0;
39 p0.setAntiAlias(aa);
40 // Set a reasonable stroke width that configureStyle can override.
41 p0.setStrokeWidth(15.f);
42 SkPaint p1 = p0;
44 // Use alpha so we see magenta on overlap between arc and its complement.
45 p0.setAlpha(100);
46 p1.setAlpha(100);
47 configureStyle(&p0);
48 configureStyle(&p1);
49
50 canvas->save();
51 canvas->translate(kPad + x, kPad + y);
52 for (auto start : kStarts) {
53 canvas->save();
54 for (auto sweep : kSweeps) {
55 canvas->drawArc(kRect, start, sweep, useCenter, p0);
56 canvas->drawArc(kRect, start, -(360.f - sweep), useCenter, p1);
57 canvas->translate(kRect.width() + kPad, 0.f);
58 }
59 canvas->restore();
60 canvas->translate(0, kRect.height() + kPad);
61 }
62 canvas->restore();
63 };
64 // Draw a grids for combo of enabling/disabling aa and using center.
65 constexpr SkScalar kGridW = kW / 2.f;
66 constexpr SkScalar kGridH = kH / 2.f;
67 drawGrid(0.f , 0.f , false, false);
68 drawGrid(kGridW, 0.f , true , false);
69 drawGrid(0.f , kGridH, false, true );
70 drawGrid(kGridW, kGridH, true , true );
71 // Draw separators between the grids.
72 SkPaint linePaint;
73 linePaint.setAntiAlias(true);
74 linePaint.setColor(SK_ColorBLACK);
75 canvas->drawLine(kGridW, 0.f , kGridW, SkIntToScalar(kH), linePaint);
76 canvas->drawLine(0.f , kGridH, SkIntToScalar(kW), kGridH, linePaint);
77}
78
79#define DEF_ARC_GM(name) DEF_SIMPLE_GM(circular_arcs_##name, canvas, kW, kH)
80
82 auto setFill = [] (SkPaint*p) { p->setStroke(false); };
83 draw_arcs(canvas, setFill);
84}
85
86DEF_ARC_GM(hairline) {
87 auto setHairline = [] (SkPaint* p) {
88 p->setStroke(true);
89 p->setStrokeWidth(0.f);
90 };
91 draw_arcs(canvas, setHairline);
92}
93
94DEF_ARC_GM(stroke_butt) {
95 auto setStroke = [](SkPaint* p) {
96 p->setStroke(true);
97 p->setStrokeCap(SkPaint::kButt_Cap);
98 };
99 draw_arcs(canvas, setStroke);
100}
101
102DEF_ARC_GM(stroke_square) {
103 auto setStroke = [] (SkPaint* p) {
104 p->setStroke(true);
105 p->setStrokeCap(SkPaint::kSquare_Cap);
106 };
107 draw_arcs(canvas, setStroke);
108}
109
110DEF_ARC_GM(stroke_round) {
111 auto setStroke = [] (SkPaint* p) {
112 p->setStroke(true);
113 p->setStrokeCap(SkPaint::kRound_Cap);
114 };
115 draw_arcs(canvas, setStroke);
116}
117
118DEF_SIMPLE_GM(circular_arcs_weird, canvas, 1000, 400) {
119 constexpr SkScalar kS = 50;
120 struct Arc {
121 SkRect fOval;
122 SkScalar fStart;
123 SkScalar fSweep;
124 };
125 const Arc noDrawArcs[] = {
126 // no sweep
127 {SkRect::MakeWH(kS, kS), 0, 0},
128 // empty rect in x
129 {SkRect::MakeWH(-kS, kS), 0, 90},
130 // empty rect in y
131 {SkRect::MakeWH(kS, -kS), 0, 90},
132 // empty rect in x and y
133 {SkRect::MakeWH( 0, 0), 0, 90},
134 };
135 const Arc arcs[] = {
136 // large start
137 {SkRect::MakeWH(kS, kS), 810.f, 90.f},
138 // large negative start
139 {SkRect::MakeWH(kS, kS), -810.f, 90.f},
140 // exactly 360 sweep
141 {SkRect::MakeWH(kS, kS), 0.f, 360.f},
142 // exactly -360 sweep
143 {SkRect::MakeWH(kS, kS), 0.f, -360.f},
144 // exactly 540 sweep
145 {SkRect::MakeWH(kS, kS), 0.f, 540.f},
146 // exactly -540 sweep
147 {SkRect::MakeWH(kS, kS), 0.f, -540.f},
148 // generic large sweep and large start
149 {SkRect::MakeWH(kS, kS), 1125.f, 990.f},
150 };
151 TArray<SkPaint> paints;
152 // fill
153 paints.push_back();
154 // stroke
155 paints.push_back().setStroke(true);
156 paints.back().setStrokeWidth(kS / 6.f);
157 // hairline
158 paints.push_back().setStroke(true);
159 paints.back().setStrokeWidth(0.f);
160 // stroke and fill
161 paints.push_back().setStyle(SkPaint::kStrokeAndFill_Style);
162 paints.back().setStrokeWidth(kS / 6.f);
163 // dash effect
164 paints.push_back().setStroke(true);
165 paints.back().setStrokeWidth(kS / 6.f);
166 constexpr SkScalar kDashIntervals[] = {kS / 15, 2 * kS / 15};
167 paints.back().setPathEffect(SkDashPathEffect::Make(kDashIntervals, 2, 0.f));
168
169 constexpr SkScalar kPad = 20.f;
170 canvas->translate(kPad, kPad);
171 // This loop should draw nothing.
172 for (auto arc : noDrawArcs) {
173 for (auto paint : paints) {
174 paint.setAntiAlias(true);
175 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
176 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
177 }
178 }
179
180 SkPaint linePaint;
181 linePaint.setAntiAlias(true);
182 linePaint.setColor(SK_ColorRED);
183 SkScalar midX = std::size(arcs) * (kS + kPad) - kPad/2.f;
184 SkScalar height = paints.size() * (kS + kPad);
185 canvas->drawLine(midX, -kPad, midX, height, linePaint);
186
187 for (auto paint : paints) {
188 paint.setAntiAlias(true);
189 canvas->save();
190 for (auto arc : arcs) {
191 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
192 canvas->translate(kS + kPad, 0.f);
193 }
194 for (auto arc : arcs) {
195 canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
196 canvas->translate(kS + kPad, 0.f);
197 }
198 canvas->restore();
199 canvas->translate(0, kS + kPad);
200 }
201}
202
203DEF_SIMPLE_GM(onebadarc, canvas, 100, 100) {
204 SkPathBuilder path;
205 path.moveTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000)); // 20, 20
206 path.lineTo(SkBits2Float(0x4208918c), SkBits2Float(0x4208918c)); // 34.1421f, 34.1421f
207 path.conicTo(SkBits2Float(0x41a00000), SkBits2Float(0x42412318), // 20, 48.2843f
208 SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c), // 5.85786f, 34.1421f
209 SkBits2Float(0x3f3504f3)); // 0.707107f
210 path.quadTo(SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c), // 5.85786f, 34.1421f
211 SkBits2Float(0x40bb73a2), SkBits2Float(0x4208918c)); // 5.85787f, 34.1421f
212 path.lineTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000)); // 20, 20
213 path.close();
214 SkPaint p0;
216 p0.setStrokeWidth(15.f);
217 p0.setStroke(true);
218 p0.setAlpha(100);
219 canvas->translate(20, 0);
220 canvas->drawPath(path.detach(), p0);
221
222 canvas->drawArc(SkRect{60, 0, 100, 40}, 45, 90, true, p0);
223}
224
225DEF_SIMPLE_GM(crbug_888453, canvas, 480, 150) {
226 // Two GPU path renderers were using a too-large tolerance when chopping connics to quads.
227 // This manifested as not-very-round circular arcs at certain radii. All the arcs being drawn
228 // here should look like circles.
229 SkPaint fill;
230 fill.setAntiAlias(true);
231 SkPaint hairline = fill;
232 hairline.setStroke(true);
233 SkPaint stroke = hairline;
234 stroke.setStrokeWidth(2.0f);
235 int x = 4;
236 int y0 = 25, y1 = 75, y2 = 125;
237 for (int r = 2; r <= 20; ++r) {
238 canvas->drawArc(SkRect::MakeXYWH(x - r, y0 - r, 2 * r, 2 * r), 0, 360, false, fill);
239 canvas->drawArc(SkRect::MakeXYWH(x - r, y1 - r, 2 * r, 2 * r), 0, 360, false, hairline);
240 canvas->drawArc(SkRect::MakeXYWH(x - r, y2 - r, 2 * r, 2 * r), 0, 360, false, stroke);
241 x += 2 * r + 4;
242 }
243}
244
245DEF_SIMPLE_GM(circular_arc_stroke_matrix, canvas, 820, 1090) {
246 static constexpr SkScalar kRadius = 40.f;
247 static constexpr SkScalar kStrokeWidth = 5.f;
248 static constexpr SkScalar kStart = 89.f;
249 static constexpr SkScalar kSweep = 180.f/SK_ScalarPI; // one radian
250
251 TArray<SkMatrix> matrices;
252 matrices.push_back().setRotate(kRadius, kRadius, 45.f);
253 matrices.push_back(SkMatrix::I());
254 matrices.push_back().setAll(-1, 0, 2*kRadius,
255 0, 1, 0,
256 0, 0, 1);
257 matrices.push_back().setAll( 1, 0, 0,
258 0, -1, 2*kRadius,
259 0, 0, 1);
260 matrices.push_back().setAll( 1, 0, 0,
261 0, -1, 2*kRadius,
262 0, 0, 1);
263 matrices.push_back().setAll( 0, -1, 2*kRadius,
264 -1, 0, 2*kRadius,
265 0, 0, 1);
266 matrices.push_back().setAll( 0, -1, 2*kRadius,
267 1, 0, 0,
268 0, 0, 1);
269 matrices.push_back().setAll( 0, 1, 0,
270 1, 0, 0,
271 0, 0, 1);
272 matrices.push_back().setAll( 0, 1, 0,
273 -1, 0, 2*kRadius,
274 0, 0, 1);
275 int baseMatrixCnt = matrices.size();
276
277
278 SkMatrix tinyCW;
279 tinyCW.setRotate(0.001f, kRadius, kRadius);
280 for (int i = 0; i < baseMatrixCnt; ++i) {
281 matrices.push_back().setConcat(matrices[i], tinyCW);
282 }
283 SkMatrix tinyCCW;
284 tinyCCW.setRotate(-0.001f, kRadius, kRadius);
285 for (int i = 0; i < baseMatrixCnt; ++i) {
286 matrices.push_back().setConcat(matrices[i], tinyCCW);
287 }
288 SkMatrix cw45;
289 cw45.setRotate(45.f, kRadius, kRadius);
290 for (int i = 0; i < baseMatrixCnt; ++i) {
291 matrices.push_back().setConcat(matrices[i], cw45);
292 }
293
294 int x = 0;
295 int y = 0;
296 static constexpr SkScalar kPad = 2*kStrokeWidth;
297 canvas->translate(kPad, kPad);
298 auto bounds = SkRect::MakeWH(2*kRadius, 2*kRadius);
300 for (const auto& m : matrices) {
302 paint.setStrokeCap(cap);
303 paint.setAntiAlias(true);
304 paint.setStroke(true);
305 paint.setStrokeWidth(kStrokeWidth);
306 canvas->save();
307 canvas->translate(x * (2*kRadius + kPad), y * (2*kRadius + kPad));
308 canvas->concat(m);
309 paint.setColor(SK_ColorRED);
310 paint.setAlpha(0x80);
311 canvas->drawArc(bounds, kStart, kSweep, false, paint);
312 paint.setColor(SK_ColorBLUE);
313 paint.setAlpha(0x80);
314 canvas->drawArc(bounds, kStart, kSweep - 360.f, false, paint);
315 canvas->restore();
316 ++x;
317 if (x == baseMatrixCnt) {
318 x = 0;
319 ++y;
320 }
321 }
322 }
323}
324
325DEF_SIMPLE_GM(crbug_1472747, canvas, 400, 400) {
326 auto addCanvas2dCircleArcTo = [](float cx, float cy, float radius, SkPath* path) {
327 SkRect oval = SkRect::MakeLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
328 // arcTo(oval, 0, 2pi, anticlockwise) gets split to 0->-180,-180->-360
329 path->arcTo(oval, 0.f, -180.f, false);
330 path->arcTo(oval, -180.f, -180.f, false);
331 };
332
333 // This manually stroked circle is large enough to trigger pre-chopping in the
334 // tessellation path renderers, but uses a non-default winding mode, which
335 // originally was not preserved in the chopped path.
336 static constexpr float kRadius = 31000.f;
337 SkPath strokedCircle;
338 addCanvas2dCircleArcTo(0.f, kRadius + 10.f, kRadius, &strokedCircle); // inner
339 addCanvas2dCircleArcTo(0.f, kRadius + 10.f, kRadius + 5.f, &strokedCircle); // outer
341
342 SkPaint fill;
343 fill.setAntiAlias(true);
344 canvas->drawPath(strokedCircle, fill);
345}
static constexpr int kS
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
static float SkBits2Float(uint32_t bits)
Definition SkFloatBits.h:48
#define SkIntToScalar(x)
Definition SkScalar.h:57
#define SK_ScalarPI
Definition SkScalar.h:21
constexpr int kPad
constexpr int kH
void draw_arcs(SkCanvas *canvas, std::function< void(SkPaint *)> configureStyle)
constexpr SkScalar kSweeps[]
constexpr SkRect kRect
#define DEF_ARC_GM(name)
constexpr SkScalar kDiameter
constexpr SkScalar kStarts[]
constexpr int kW
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
void drawArc(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint &paint)
int save()
Definition SkCanvas.cpp:451
void drawPath(const SkPath &path, const SkPaint &paint)
void concat(const SkMatrix &matrix)
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition SkMatrix.cpp:452
static const SkMatrix & I()
@ kRound_Cap
adds circle
Definition SkPaint.h:335
@ kButt_Cap
no stroke extension
Definition SkPaint.h:334
@ kSquare_Cap
adds square
Definition SkPaint.h:336
void setColor(SkColor color)
Definition SkPaint.cpp:119
void setAntiAlias(bool aa)
Definition SkPaint.h:170
@ kStrokeAndFill_Style
sets to stroke and fill geometry
Definition SkPaint.h:195
void setAlpha(U8CPU a)
Definition SkPaint.h:279
void setStroke(bool)
Definition SkPaint.cpp:115
void setStrokeWidth(SkScalar width)
Definition SkPaint.cpp:159
void setFillType(SkPathFillType ft)
Definition SkPath.h:235
int size() const
Definition SkTArray.h:416
const Paint & paint
float SkScalar
Definition extension.cpp:12
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50
double y
double x
int32_t height
constexpr SkScalar kStrokeWidth
constexpr int kRadius
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition SkRect.h:659
constexpr float height() const
Definition SkRect.h:769
constexpr float width() const
Definition SkRect.h:762
static constexpr SkRect MakeWH(float w, float h)
Definition SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition SkRect.h:646