Flutter Engine
The Flutter Engine
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
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) {
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);
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
DEF_SIMPLE_GM(circular_arcs_weird, canvas, 1000, 400)
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:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
void drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint &paint)
Definition: SkCanvas.cpp:2700
void drawArc(const SkRect &oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter, const SkPaint &paint)
Definition: SkCanvas.cpp:2728
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
Definition: SkMatrix.h:562
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:452
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
SkMatrix & setConcat(const SkMatrix &a, const SkMatrix &b)
Definition: SkMatrix.cpp:603
@ 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 setStyle(Style style)
Definition: SkPaint.cpp:105
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 setPathEffect(sk_sp< SkPathEffect > pathEffect)
void setStroke(bool)
Definition: SkPaint.cpp:115
void setStrokeWidth(SkScalar width)
Definition: SkPaint.cpp:159
Definition: SkPath.h:59
void setFillType(SkPathFillType ft)
Definition: SkPath.h:235
int size() const
Definition: SkTArray.h:421
const Paint & paint
Definition: color_source.cc:38
float SkScalar
Definition: extension.cpp:12
Dart_NativeFunction function
Definition: fuchsia.cc:51
double y
double x
Optional< SkRect > bounds
Definition: SkRecords.h:189
SkRect oval
Definition: SkRecords.h:249
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
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