Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
concavepaths.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
14namespace {
15// Concave test
16void test_concave(SkCanvas* canvas, const SkPaint& paint) {
17 canvas->translate(0, 0);
18 canvas->drawPath(SkPath::Polygon({{20,20}, {80,20}, {30,30}, {20,80}}, false), paint);
19}
20
21// Reverse concave test
22void test_reverse_concave(SkCanvas* canvas, const SkPaint& paint) {
23 canvas->save();
24 canvas->translate(100, 0);
25 canvas->drawPath(SkPath::Polygon({{20,20}, {20,80}, {30,30}, {80,20}}, false), paint);
26 canvas->restore();
27}
28
29// Bowtie (intersection)
30void test_bowtie(SkCanvas* canvas, const SkPaint& paint) {
31 canvas->save();
32 canvas->translate(200, 0);
33 canvas->drawPath(SkPath::Polygon({{20,20}, {80,80}, {80,20}, {20,80}}, false), paint);
34 canvas->restore();
35}
36
37// "fake" bowtie (concave, but no intersection)
38void test_fake_bowtie(SkCanvas* canvas, const SkPaint& paint) {
39 canvas->save();
40 canvas->translate(300, 0);
41 canvas->drawPath(SkPath::Polygon({{20,20}, {50,40}, {80,20}, {80,80}, {50,60}, {20,80}},
42 false), paint);
43 canvas->restore();
44}
45
46// Bowtie with a smaller right hand lobe. The outer vertex of the left hand
47// lobe intrudes into the interior of the right hand lobe.
48void test_intruding_vertex(SkCanvas* canvas, const SkPaint& paint) {
49 canvas->save();
50 canvas->translate(400, 0);
51 canvas->drawPath(SkPath::Polygon({{20,20}, {50,50}, {68,20}, {68,80}, {50,50}, {20,80}},
52 false, SkPathFillType::kWinding, true), paint);
53 canvas->restore();
54}
55
56// A shape with an edge that becomes inverted on AA stroking and that also contains
57// a repeated start/end vertex.
58void test_inversion_repeat_vertex(SkCanvas* canvas, const SkPaint& paint) {
59 canvas->save();
60 canvas->translate(400, 100);
61 const SkPoint pts[] = {
62 {80,50}, {40,80}, {60,20}, {20,20}, {39.99f,80}, {80,50},
63 };
64 canvas->drawPath(SkPath::Polygon(pts, std::size(pts), false,
66 canvas->restore();
67}
68
69// Fish test (intersection/concave)
70void test_fish(SkCanvas* canvas, const SkPaint& paint) {
71 canvas->save();
72 canvas->translate(0, 100);
73 canvas->drawPath(SkPath::Polygon({{20,20}, {80,80}, {70,50}, {80,20}, {20,80}, {0,50}}, false,
75 canvas->restore();
76}
77
78// Overlapping "Fast-forward" icon: tests coincidence of inner and outer
79// vertices generated by intersection.
80void test_fast_forward(SkCanvas* canvas, const SkPaint& paint) {
81 canvas->save();
82 canvas->translate(100, 100);
83 auto path = SkPathBuilder().addPolygon({{20,20}, {60,50}, {20,80}}, false)
84 .addPolygon({{40,20}, {40,80}, {80,50}}, false)
85 .detach();
86 canvas->drawPath(path, paint);
87 canvas->restore();
88}
89
90// Square polygon with a square hole.
91void test_hole(SkCanvas* canvas, const SkPaint& paint) {
92 canvas->save();
93 canvas->translate(200, 100);
94 auto path = SkPathBuilder().addPolygon({{20,20}, {80,20}, {80,80}, {20,80}}, false)
95 .addPolygon({{30,30}, {30,70}, {70,70}, {70,30}}, false)
96 .detach();
97 canvas->drawPath(path, paint);
98 canvas->restore();
99}
100
101// Star test (self-intersecting)
102void test_star(SkCanvas* canvas, const SkPaint& paint) {
103 canvas->save();
104 canvas->translate(300, 100);
105 canvas->drawPath(SkPath::Polygon({{30,20}, {50,80}, {70,20}, {20,57}, {80,57}}, false),
106 paint);
107 canvas->restore();
108}
109
110// Exercise a case where the intersection is below a bottom edge.
111void test_twist(SkCanvas* canvas, const SkPaint& paint) {
112 canvas->save();
113 canvas->translate(420, 220);
114 canvas->scale(10, 10);
115 const SkPoint pts[] = {
116 {0.5f, 6},
117 {5.8070392608642578125f, 6.4612660408020019531f},
118 {-2.9186885356903076172f, 2.811046600341796875f},
119 {0.49999994039535522461f, -1.4124038219451904297f},
120 };
121 canvas->drawPath(SkPath::Polygon(pts, std::size(pts), false), paint);
122 canvas->restore();
123}
124
125// Stairstep with repeated vert (intersection)
126void test_stairstep(SkCanvas* canvas, const SkPaint& paint) {
127 canvas->save();
128 canvas->translate(0, 200);
129 canvas->drawPath(SkPath::Polygon({{50,50}, {50,20}, {80,20}, {50,50}, {20,50}, {20,80}}, false),
130 paint);
131 canvas->restore();
132}
133
134void test_stairstep2(SkCanvas* canvas, const SkPaint& paint) {
135 canvas->save();
136 canvas->translate(100, 200);
137 canvas->drawPath(SkPath::Polygon({{20,60}, {35,80}, {50,60}, {65,80}, {80,60}}, false), paint);
138 canvas->restore();
139}
140
141// Overlapping segments
142void test_overlapping(SkCanvas* canvas, const SkPaint& paint) {
143 canvas->save();
144 canvas->translate(200, 200);
145 canvas->drawPath(SkPath::Polygon({{20,80}, {80,80}, {80,20}, {80,30}}, false), paint);
146 canvas->restore();
147}
148
149// Two "island" triangles inside a containing rect.
150// This exercises the partnering code in the tessellator.
151void test_partners(SkCanvas* canvas, const SkPaint& paint) {
152 canvas->save();
153 canvas->translate(300, 200);
154 auto path = SkPathBuilder().addPolygon({{20,80}, {80,80}, {80,20}, {20,20}}, false)
155 .addPolygon({{30,30}, {45,50}, {30,70}}, false)
156 .addPolygon({{70,30}, {70,70}, {55,50}}, false)
157 .detach();
158 canvas->drawPath(path, paint);
159 canvas->restore();
160}
161
162// A split edge causes one half to be merged to zero winding (destroyed).
163// Test that the other half of the split doesn't also get zero winding.
164void test_winding_merged_to_zero(SkCanvas* canvas, const SkPaint& paint) {
166 canvas->save();
167 canvas->translate(400, 350);
168 path.moveTo(20, 80);
169 path.moveTo(70, -0.000001f);
170 path.lineTo(70, 0.0);
171 path.lineTo(60, -30.0);
172 path.lineTo(40, 20.0);
173 path.moveTo(50, 50.0);
174 path.lineTo(50, -50.0);
175 path.lineTo(10, 50.0);
176 canvas->drawPath(path.detach(), paint);
177 canvas->restore();
178}
179
180// Monotone test 1 (point in the middle)
181void test_monotone_1(SkCanvas* canvas, const SkPaint& paint) {
183 canvas->save();
184 canvas->translate(0, 300);
185 path.moveTo(20, 20);
186 path.quadTo(20, 50, 80, 50);
187 path.quadTo(20, 50, 20, 80);
188 canvas->drawPath(path.detach(), paint);
189 canvas->restore();
190}
191
192// Monotone test 2 (point at the top)
193void test_monotone_2(SkCanvas* canvas, const SkPaint& paint) {
195 canvas->save();
196 canvas->translate(100, 300);
197 path.moveTo(20, 20);
198 path.lineTo(80, 30);
199 path.quadTo(20, 20, 20, 80);
200 canvas->drawPath(path.detach(), paint);
201 canvas->restore();
202}
203
204// Monotone test 3 (point at the bottom)
205void test_monotone_3(SkCanvas* canvas, const SkPaint& paint) {
207 canvas->save();
208 canvas->translate(200, 300);
209 path.moveTo(20, 80);
210 path.lineTo(80, 70);
211 path.quadTo(20, 80, 20, 20);
212 canvas->drawPath(path.detach(), paint);
213 canvas->restore();
214}
215
216// Monotone test 4 (merging of two monotones)
217void test_monotone_4(SkCanvas* canvas, const SkPaint& paint) {
219 canvas->save();
220 canvas->translate(300, 300);
221 path.moveTo(80, 25);
222 path.lineTo(50, 39);
223 path.lineTo(20, 25);
224 path.lineTo(40, 45);
225 path.lineTo(70, 50);
226 path.lineTo(80, 80);
227 canvas->drawPath(path.detach(), paint);
228 canvas->restore();
229}
230
231// Monotone test 5 (aborted merging of two monotones)
232void test_monotone_5(SkCanvas* canvas, const SkPaint& paint) {
234 canvas->save();
235 canvas->translate(0, 400);
236 path.moveTo(50, 20);
237 path.lineTo(80, 80);
238 path.lineTo(50, 50);
239 path.lineTo(20, 80);
240 canvas->drawPath(path.detach(), paint);
241 canvas->restore();
242}
243// Degenerate intersection test
244void test_degenerate(SkCanvas* canvas, const SkPaint& paint) {
246 canvas->save();
247 canvas->translate(100, 400);
248 path.moveTo(50, 20);
249 path.lineTo(70, 30);
250 path.lineTo(20, 50);
251 path.moveTo(50, 20);
252 path.lineTo(80, 80);
253 path.lineTo(50, 80);
254 canvas->drawPath(path.detach(), paint);
255 canvas->restore();
256}
257// Two triangles with a coincident edge.
258void test_coincident_edge(SkCanvas* canvas, const SkPaint& paint) {
260 canvas->save();
261 canvas->translate(200, 400);
262
263 path.moveTo(80, 20);
264 path.lineTo(80, 80);
265 path.lineTo(20, 80);
266
267 path.moveTo(20, 20);
268 path.lineTo(80, 80);
269 path.lineTo(20, 80);
270
271 canvas->drawPath(path.detach(), paint);
272 canvas->restore();
273}
274// Bowtie with a coincident triangle (one triangle vertex coincident with the
275// bowtie's intersection).
276void test_bowtie_coincident_triangle(SkCanvas* canvas, const SkPaint& paint) {
278 canvas->save();
279 canvas->translate(300, 400);
280 path.moveTo(20, 20);
281 path.lineTo(80, 80);
282 path.lineTo(80, 20);
283 path.lineTo(20, 80);
284 path.moveTo(50, 50);
285 path.lineTo(80, 20);
286 path.lineTo(80, 80);
287 canvas->drawPath(path.detach(), paint);
288 canvas->restore();
289}
290
291// Collinear outer boundary edges. In the edge-AA codepath, this creates an overlap region
292// which contains a boundary edge. It can't be removed, but it must have the correct winding.
293void test_collinear_outer_boundary_edge(SkCanvas* canvas, const SkPaint& paint) {
295 canvas->save();
296 canvas->translate(400, 400);
297 path.moveTo(20, 20);
298 path.lineTo(20, 50);
299 path.lineTo(50, 50);
300 path.moveTo(80, 50);
301 path.lineTo(50, 50);
302 path.lineTo(80, 20);
303 canvas->drawPath(path.detach(), paint);
304 canvas->restore();
305}
306
307// Coincident edges (big ones first, coincident vert on top).
308void test_coincident_edges_1(SkCanvas* canvas, const SkPaint& paint) {
310 canvas->save();
311 canvas->translate(0, 500);
312 path.moveTo(20, 20);
313 path.lineTo(80, 80);
314 path.lineTo(20, 80);
315 path.moveTo(20, 20);
316 path.lineTo(50, 50);
317 path.lineTo(20, 50);
318 canvas->drawPath(path.detach(), paint);
319 canvas->restore();
320}
321// Coincident edges (small ones first, coincident vert on top).
322void test_coincident_edges_2(SkCanvas* canvas, const SkPaint& paint) {
324 canvas->save();
325 canvas->translate(100, 500);
326 path.moveTo(20, 20);
327 path.lineTo(50, 50);
328 path.lineTo(20, 50);
329 path.moveTo(20, 20);
330 path.lineTo(80, 80);
331 path.lineTo(20, 80);
332 canvas->drawPath(path.detach(), paint);
333 canvas->restore();
334}
335// Coincident edges (small ones first, coincident vert on bottom).
336void test_coincident_edges_3(SkCanvas* canvas, const SkPaint& paint) {
338 canvas->save();
339 canvas->translate(200, 500);
340 path.moveTo(20, 80);
341 path.lineTo(20, 50);
342 path.lineTo(50, 50);
343 path.moveTo(20, 80);
344 path.lineTo(20, 20);
345 path.lineTo(80, 20);
346 canvas->drawPath(path.detach(), paint);
347 canvas->restore();
348}
349// Coincident edges (big ones first, coincident vert on bottom).
350void test_coincident_edges_4(SkCanvas* canvas, const SkPaint& paint) {
352 canvas->save();
353 canvas->translate(300, 500);
354 path.moveTo(20, 80);
355 path.lineTo(20, 20);
356 path.lineTo(80, 20);
357 path.moveTo(20, 80);
358 path.lineTo(20, 50);
359 path.lineTo(50, 50);
360 canvas->drawPath(path.detach(), paint);
361 canvas->restore();
362}
363
364} // namespace
365
366DEF_SIMPLE_GM(concavepaths, canvas, 500, 600) {
368
369 paint.setAntiAlias(true);
370 paint.setStyle(SkPaint::kFill_Style);
371
372 test_concave(canvas, paint);
373 test_reverse_concave(canvas, paint);
374 test_bowtie(canvas, paint);
375 test_fake_bowtie(canvas, paint);
376 test_intruding_vertex(canvas, paint);
377 test_fish(canvas, paint);
378 test_fast_forward(canvas, paint);
379 test_hole(canvas, paint);
380 test_star(canvas, paint);
381 test_twist(canvas, paint);
382 test_inversion_repeat_vertex(canvas, paint);
383 test_stairstep(canvas, paint);
384 test_stairstep2(canvas, paint);
385 test_overlapping(canvas, paint);
386 test_partners(canvas, paint);
387 test_winding_merged_to_zero(canvas, paint);
388 test_monotone_1(canvas, paint);
389 test_monotone_2(canvas, paint);
390 test_monotone_3(canvas, paint);
391 test_monotone_4(canvas, paint);
392 test_monotone_5(canvas, paint);
393 test_degenerate(canvas, paint);
394 test_coincident_edge(canvas, paint);
395 test_bowtie_coincident_triangle(canvas, paint);
396 test_collinear_outer_boundary_edge(canvas, paint);
397 test_coincident_edges_1(canvas, paint);
398 test_coincident_edges_2(canvas, paint);
399 test_coincident_edges_3(canvas, paint);
400 test_coincident_edges_4(canvas, paint);
401}
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
int save()
Definition SkCanvas.cpp:451
void drawPath(const SkPath &path, const SkPaint &paint)
void scale(SkScalar sx, SkScalar sy)
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
SkPathBuilder & addPolygon(const SkPoint pts[], int count, bool isClosed)
static SkPath Polygon(const SkPoint pts[], int count, bool isClosed, SkPathFillType=SkPathFillType::kWinding, bool isVolatile=false)
Definition SkPath.cpp:3546
const Paint & paint
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
Definition gm.h:50
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