Flutter Engine
The Flutter Engine
convex_all_line_paths.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2015 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"
13#include "include/core/SkPath.h"
15#include "include/core/SkRect.h"
17#include "include/core/SkSize.h"
20#include "src/core/SkPathPriv.h"
21
22#include <memory>
23
24static void create_ngon(int n, SkPoint* pts, SkScalar width, SkScalar height) {
25 float angleStep = 360.0f / n, angle = 0.0f;
26 if ((n % 2) == 1) {
27 angle = angleStep/2.0f;
28 }
29
30 for (int i = 0; i < n; ++i) {
31 pts[i].fX = -SkScalarSin(SkDegreesToRadians(angle)) * width;
32 pts[i].fY = SkScalarCos(SkDegreesToRadians(angle)) * height;
33 angle += angleStep;
34 }
35}
36
38// narrow rect
39const SkPoint gPoints0[] = {
40 { -1.5f, -50.0f },
41 { 1.5f, -50.0f },
42 { 1.5f, 50.0f },
43 { -1.5f, 50.0f }
44};
45// narrow rect on an angle
46const SkPoint gPoints1[] = {
47 { -50.0f, -49.0f },
48 { -49.0f, -50.0f },
49 { 50.0f, 49.0f },
50 { 49.0f, 50.0f }
51};
52// trap - narrow on top - wide on bottom
53const SkPoint gPoints2[] = {
54 { -10.0f, -50.0f },
55 { 10.0f, -50.0f },
56 { 50.0f, 50.0f },
57 { -50.0f, 50.0f }
58};
59// wide skewed rect
60const SkPoint gPoints3[] = {
61 { -50.0f, -50.0f },
62 { 0.0f, -50.0f },
63 { 50.0f, 50.0f },
64 { 0.0f, 50.0f }
65};
66// thin rect with colinear-ish lines
67const SkPoint gPoints4[] = {
68 { -6.0f, -50.0f },
69 { 4.0f, -50.0f },
70 { 5.0f, -25.0f }, // remove if collinear diagonal points are not concave
71 { 6.0f, 0.0f },
72 { 5.0f, 25.0f }, // remove if collinear diagonal points are not concave
73 { 4.0f, 50.0f },
74 { -4.0f, 50.0f }
75};
76// degenerate
77const SkPoint gPoints5[] = {
78 { -0.025f, -0.025f },
79 { 0.025f, -0.025f },
80 { 0.025f, 0.025f },
81 { -0.025f, 0.025f }
82};
83// Triangle in which the first point should fuse with last
84const SkPoint gPoints6[] = {
85 { -20.0f, -13.0f },
86 { -20.0f, -13.05f },
87 { 20.0f, -13.0f },
88 { 20.0f, 27.0f }
89};
90// thin rect with colinear lines
91const SkPoint gPoints7[] = {
92 { -10.0f, -50.0f },
93 { 10.0f, -50.0f },
94 { 10.0f, -25.0f },
95 { 10.0f, 0.0f },
96 { 10.0f, 25.0f },
97 { 10.0f, 50.0f },
98 { -10.0f, 50.0f }
99};
100// capped teardrop
101const SkPoint gPoints8[] = {
102 { 50.00f, 50.00f },
103 { 0.00f, 50.00f },
104 { -15.45f, 47.55f },
105 { -29.39f, 40.45f },
106 { -40.45f, 29.39f },
107 { -47.55f, 15.45f },
108 { -50.00f, 0.00f },
109 { -47.55f, -15.45f },
110 { -40.45f, -29.39f },
111 { -29.39f, -40.45f },
112 { -15.45f, -47.55f },
113 { 0.00f, -50.00f },
114 { 50.00f, -50.00f }
115};
116// teardrop
117const SkPoint gPoints9[] = {
118 { 4.39f, 40.45f },
119 { -9.55f, 47.55f },
120 { -25.00f, 50.00f },
121 { -40.45f, 47.55f },
122 { -54.39f, 40.45f },
123 { -65.45f, 29.39f },
124 { -72.55f, 15.45f },
125 { -75.00f, 0.00f },
126 { -72.55f, -15.45f },
127 { -65.45f, -29.39f },
128 { -54.39f, -40.45f },
129 { -40.45f, -47.55f },
130 { -25.0f, -50.0f },
131 { -9.55f, -47.55f },
132 { 4.39f, -40.45f },
133 { 75.00f, 0.00f }
134};
135// clipped triangle
137 { -10.0f, -50.0f },
138 { 10.0f, -50.0f },
139 { 50.0f, 31.0f },
140 { 40.0f, 50.0f },
141 { -40.0f, 50.0f },
142 { -50.0f, 31.0f },
143};
144
145const SkPoint* gPoints[] = {
148};
149
150const size_t gSizes[] = {
162};
163static_assert(std::size(gSizes) == std::size(gPoints), "array_mismatch");
164} // namespace ConvexLineOnlyData
165
166namespace skiagm {
167
168// This GM is intended to exercise Ganesh's handling of convex line-only
169// paths
170class ConvexLineOnlyPathsGM : public GM {
171public:
172 ConvexLineOnlyPathsGM(bool doStrokeAndFill) : fDoStrokeAndFill(doStrokeAndFill) {
173 this->setBGColor(0xFFFFFFFF);
174 }
175
176protected:
177 SkString getName() const override {
178 if (fDoStrokeAndFill) {
179 return SkString("convex-lineonly-paths-stroke-and-fill");
180 }
181 return SkString("convex-lineonly-paths");
182 }
183 SkISize getISize() override { return SkISize::Make(kGMWidth, kGMHeight); }
184 bool runAsBench() const override { return true; }
185
186 static SkPath GetPath(int index, SkPathDirection dir) {
187 std::unique_ptr<SkPoint[]> data(nullptr);
188 const SkPoint* points;
189 int numPts;
190 if (index < (int) std::size(ConvexLineOnlyData::gPoints)) {
191 // manually specified
193 numPts = (int)ConvexLineOnlyData::gSizes[index];
194 } else {
195 // procedurally generated
196 SkScalar width = kMaxPathHeight/2;
197 SkScalar height = kMaxPathHeight/2;
198 switch (index-std::size(ConvexLineOnlyData::gPoints)) {
199 case 0:
200 numPts = 3;
201 break;
202 case 1:
203 numPts = 4;
204 break;
205 case 2:
206 numPts = 5;
207 break;
208 case 3: // squashed pentagon
209 numPts = 5;
210 width = kMaxPathHeight/5;
211 break;
212 case 4:
213 numPts = 6;
214 break;
215 case 5:
216 numPts = 8;
217 break;
218 case 6: // squashed octogon
219 numPts = 8;
220 width = kMaxPathHeight/5;
221 break;
222 case 7:
223 numPts = 20;
224 break;
225 case 8:
226 numPts = 100;
227 break;
228 default:
229 numPts = 3;
230 break;
231 }
232
233 data = std::make_unique<SkPoint[]>(numPts);
234
235 create_ngon(numPts, data.get(), width, height);
236 points = data.get();
237 }
238
240
241 if (SkPathDirection::kCW == dir) {
242 builder.moveTo(points[0]);
243 for (int i = 1; i < numPts; ++i) {
244 builder.lineTo(points[i]);
245 }
246 } else {
247 builder.moveTo(points[numPts-1]);
248 for (int i = numPts-2; i >= 0; --i) {
249 builder.lineTo(points[i]);
250 }
251 }
252
253 builder.close();
254 SkPath path = builder.detach();
255#ifdef SK_DEBUG
256 // Each path this method returns should be convex, only composed of
257 // lines, wound the right direction, and short enough to fit in one
258 // of the GMs rows.
259 SkASSERT(path.isConvex());
260 SkASSERT(SkPath::kLine_SegmentMask == path.getSegmentMasks());
263 SkRect bounds = path.getBounds();
264 SkASSERT(SkScalarNearlyEqual(bounds.centerX(), 0.0f));
265 SkASSERT(bounds.height() <= kMaxPathHeight);
266#endif
267 return path;
268 }
269
270 // Draw a single path several times, shrinking it, flipping its direction
271 // and changing its start vertex each time.
272 void drawPath(SkCanvas* canvas, int index, SkPoint* offset) {
273
274 SkPoint center;
275 {
277 if (offset->fX+path.getBounds().width() > kGMWidth) {
278 offset->fX = 0;
279 offset->fY += kMaxPathHeight;
280 if (fDoStrokeAndFill) {
281 offset->fX += kStrokeWidth / 2.0f;
282 offset->fY += kStrokeWidth / 2.0f;
283 }
284 }
285 center = { offset->fX + SkScalarHalf(path.getBounds().width()), offset->fY};
286 offset->fX += path.getBounds().width();
287 if (fDoStrokeAndFill) {
288 offset->fX += kStrokeWidth;
289 }
290 }
291
294 const float scales[] = { 1.0f, 0.75f, 0.5f, 0.25f, 0.1f, 0.01f, 0.001f };
295 const SkPaint::Join joins[3] = { SkPaint::kRound_Join,
298
300 paint.setAntiAlias(true);
301
302 for (size_t i = 0; i < std::size(scales); ++i) {
303 SkPath path = GetPath(index, dirs[i%2]);
304 if (fDoStrokeAndFill) {
306 paint.setStrokeJoin(joins[i%3]);
307 paint.setStrokeWidth(SkIntToScalar(kStrokeWidth));
308 }
309
310 canvas->save();
311 canvas->translate(center.fX, center.fY);
312 canvas->scale(scales[i], scales[i]);
313 paint.setColor(colors[i%2]);
314 canvas->drawPath(path, paint);
315 canvas->restore();
316 }
317 }
318
319 void onDraw(SkCanvas* canvas) override {
320 // the right edge of the last drawn path
321 SkPoint offset = { 0, SkScalarHalf(kMaxPathHeight) };
322 if (fDoStrokeAndFill) {
323 offset.fX += kStrokeWidth / 2.0f;
324 offset.fY += kStrokeWidth / 2.0f;
325 }
326
327 for (int i = 0; i < kNumPaths; ++i) {
328 this->drawPath(canvas, i, &offset);
329 }
330
331 {
332 // Repro for crbug.com/472723 (Missing AA on portions of graphic with GPU rasterization)
333
334 SkPaint p;
335 p.setAntiAlias(true);
336 if (fDoStrokeAndFill) {
338 p.setStrokeJoin(SkPaint::kMiter_Join);
339 p.setStrokeWidth(SkIntToScalar(kStrokeWidth));
340 }
341
343 {60.8522949f, 364.671021f},
344 {59.4380493f, 364.671021f},
345 {385.414276f, 690.647217f},
346 {386.121399f, 689.940125f},
347 }, false);
348 canvas->save();
349 canvas->translate(356.0f, 50.0f);
350 canvas->drawPath(p1, p);
351 canvas->restore();
352
353 // Repro for crbug.com/869172 (SVG path incorrectly simplified when using GPU
354 // Rasterization). This will only draw anything in the stroke-and-fill version.
356 {10.f, 0.f},
357 {38.f, 0.f},
358 {66.f, 0.f},
359 {94.f, 0.f},
360 {122.f, 0.f},
361 {150.f, 0.f},
362 {150.f, 0.f},
363 {122.f, 0.f},
364 {94.f, 0.f},
365 {66.f, 0.f},
366 {38.f, 0.f},
367 {10.f, 0.f},
368 }, true);
369 canvas->save();
370 canvas->translate(0.0f, 500.0f);
371 canvas->drawPath(p2, p);
372 canvas->restore();
373
374 // Repro for crbug.com/856137. This path previously caused GrAAConvexTessellator to turn
375 // inset rings into outsets when adjacent bisector angles converged outside the previous
376 // ring due to accumulated error.
378 {1184.96f, 982.557f},
379 {1183.71f, 982.865f},
380 {1180.99f, 982.734f},
381 {1178.5f, 981.541f},
382 {1176.35f, 979.367f},
383 {1178.94f, 938.854f},
384 {1181.35f, 936.038f},
385 {1183.96f, 934.117f},
386 {1186.67f, 933.195f},
387 {1189.36f, 933.342f},
388 {1191.58f, 934.38f},
389 }, true, SkPathFillType::kEvenOdd);
390 canvas->save();
391 SkMatrix m;
392 m.setAll(0.0893210843f, 0, 79.1197586f, 0, 0.0893210843f, 300, 0, 0, 1);
393 canvas->concat(m);
394 canvas->drawPath(p3, p);
395 canvas->restore();
396 }
397 }
398
399private:
400 inline static constexpr int kStrokeWidth = 10;
401 inline static constexpr int kNumPaths = 20;
402 inline static constexpr int kMaxPathHeight = 100;
403 inline static constexpr int kGMWidth = 512;
404 inline static constexpr int kGMHeight = 512;
405
406 bool fDoStrokeAndFill;
407
408 using INHERITED = GM;
409};
410
411//////////////////////////////////////////////////////////////////////////////
412
413DEF_GM(return new ConvexLineOnlyPathsGM(false);)
414DEF_GM(return new ConvexLineOnlyPathsGM(true);)
415} // namespace skiagm
static const int points[]
#define SkASSERT(cond)
Definition: SkAssert.h:116
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
SkPathFirstDirection
Definition: SkPathEnums.h:19
SkPathDirection
Definition: SkPathTypes.h:34
#define SkDegreesToRadians(degrees)
Definition: SkScalar.h:77
#define SkScalarSin(radians)
Definition: SkScalar.h:45
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
#define SkScalarHalf(a)
Definition: SkScalar.h:75
#define SkIntToScalar(x)
Definition: SkScalar.h:57
#define SkScalarCos(radians)
Definition: SkScalar.h:46
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
int save()
Definition: SkCanvas.cpp:447
void drawPath(const SkPath &path, const SkPaint &paint)
Definition: SkCanvas.cpp:1747
void scale(SkScalar sx, SkScalar sy)
Definition: SkCanvas.cpp:1289
void concat(const SkMatrix &matrix)
Definition: SkCanvas.cpp:1318
@ kStrokeAndFill_Style
sets to stroke and fill geometry
Definition: SkPaint.h:195
@ kRound_Join
adds circle
Definition: SkPaint.h:360
@ kMiter_Join
extends to miter limit
Definition: SkPaint.h:359
@ kBevel_Join
connects outside edges
Definition: SkPaint.h:361
static SkPathFirstDirection AsFirstDirection(SkPathDirection dir)
Definition: SkPathPriv.h:43
static SkPathFirstDirection ComputeFirstDirection(const SkPath &)
Definition: SkPath.cpp:2627
Definition: SkPath.h:59
@ kLine_SegmentMask
Definition: SkPath.h:1445
static SkPath Polygon(const SkPoint pts[], int count, bool isClosed, SkPathFillType=SkPathFillType::kWinding, bool isVolatile=false)
Definition: SkPath.cpp:3614
static SkPath GetPath(int index, SkPathDirection dir)
void drawPath(SkCanvas *canvas, int index, SkPoint *offset)
void onDraw(SkCanvas *canvas) override
ConvexLineOnlyPathsGM(bool doStrokeAndFill)
SkString getName() const override
Definition: gm.h:110
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition: gm.cpp:81
SkScalar width()
Definition: gm.h:159
SkScalar height()
Definition: gm.h:162
void setBGColor(SkColor)
Definition: gm.cpp:159
const Paint & paint
Definition: color_source.cc:38
static void create_ngon(int n, SkPoint *pts, SkScalar width, SkScalar height)
float SkScalar
Definition: extension.cpp:12
Optional< SkRect > bounds
Definition: SkRecords.h:189
PODArray< SkColor > colors
Definition: SkRecords.h:276
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
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets dir
Definition: switches.h:145
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
DEF_GM(return F(C(clipbox), 0.0f, 0.0f, {})) DEF_GM(return F(C(clipbox)
int32_t height
int32_t width
SeparatedVector2 offset
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
float fX
x-axis value
Definition: SkPoint_impl.h:164
float fY
y-axis value
Definition: SkPoint_impl.h:165
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63