blob: 890f6c0855565b69e2a31fca1345d8b02f0ac8c5 [file] [log] [blame]
senorblancod6ed19c2015-02-26 06:58:17 -08001/*
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.h"
9#include "SkCanvas.h"
bungemand3ebb482015-08-05 13:57:49 -070010#include "SkPath.h"
senorblancod6ed19c2015-02-26 06:58:17 -080011
senorblancod6ed19c2015-02-26 06:58:17 -080012namespace {
13// Concave test
14void test_concave(SkCanvas* canvas, const SkPaint& paint) {
15 SkPath path;
16 canvas->translate(0, 0);
17 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
18 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
19 path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
20 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
21 canvas->drawPath(path, paint);
22}
23
24// Reverse concave test
25void test_reverse_concave(SkCanvas* canvas, const SkPaint& paint) {
26 SkPath path;
27 canvas->save();
28 canvas->translate(100, 0);
29 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
30 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
31 path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
32 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
33 canvas->drawPath(path, paint);
34 canvas->restore();
35}
36
37// Bowtie (intersection)
38void test_bowtie(SkCanvas* canvas, const SkPaint& paint) {
39 SkPath path;
40 canvas->save();
41 canvas->translate(200, 0);
42 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
43 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
44 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
45 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
46 canvas->drawPath(path, paint);
47 canvas->restore();
48}
49
50// "fake" bowtie (concave, but no intersection)
51void test_fake_bowtie(SkCanvas* canvas, const SkPaint& paint) {
52 SkPath path;
53 canvas->save();
54 canvas->translate(300, 0);
55 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
56 path.lineTo(SkIntToScalar(50), SkIntToScalar(40));
57 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
58 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
59 path.lineTo(SkIntToScalar(50), SkIntToScalar(60));
60 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
61 canvas->drawPath(path, paint);
62 canvas->restore();
63}
64
Stephen White5926f2d2017-02-13 13:55:42 -050065// Bowtie with a smaller right hand lobe. The outer vertex of the left hand
66// lobe intrudes into the interior of the right hand lobe.
67void test_intruding_vertex(SkCanvas* canvas, const SkPaint& paint) {
68 SkPath path;
69 canvas->save();
70 canvas->translate(400, 0);
71 path.setIsVolatile(true);
72 path.moveTo(20, 20);
73 path.lineTo(50, 50);
74 path.lineTo(68, 20);
75 path.lineTo(68, 80);
76 path.lineTo(50, 50);
77 path.lineTo(20, 80);
78 canvas->drawPath(path, paint);
79 canvas->restore();
80}
81
82// A shape with an edge that becomes inverted on AA stroking and that also contains
83// a repeated start/end vertex.
84void test_inversion_repeat_vertex(SkCanvas* canvas, const SkPaint& paint) {
85 SkPath path;
86 canvas->save();
87 canvas->translate(400, 100);
88 path.setIsVolatile(true);
89 path.moveTo(80, 50);
90 path.lineTo(40, 80);
91 path.lineTo(60, 20);
92 path.lineTo(20, 20);
93 path.lineTo(39.99f, 80);
94 path.lineTo(80, 50);
95 canvas->drawPath(path, paint);
96 canvas->restore();
97}
98
senorblancod6ed19c2015-02-26 06:58:17 -080099// Fish test (intersection/concave)
100void test_fish(SkCanvas* canvas, const SkPaint& paint) {
101 SkPath path;
102 canvas->save();
103 canvas->translate(0, 100);
104 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
105 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
106 path.lineTo(SkIntToScalar(70), SkIntToScalar(50));
107 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
108 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
109 path.lineTo(SkIntToScalar(0), SkIntToScalar(50));
110 canvas->drawPath(path, paint);
111 canvas->restore();
112}
113
Stephen White2f4686f2017-01-03 16:20:01 -0500114// Overlapping "Fast-forward" icon: tests coincidence of inner and outer
115// vertices generated by intersection.
116void test_fast_forward(SkCanvas* canvas, const SkPaint& paint) {
senorblancod6ed19c2015-02-26 06:58:17 -0800117 SkPath path;
118 canvas->save();
119 canvas->translate(100, 100);
120 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
Stephen White2f4686f2017-01-03 16:20:01 -0500121 path.lineTo(SkIntToScalar(60), SkIntToScalar(50));
122 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
123 path.moveTo(SkIntToScalar(40), SkIntToScalar(20));
124 path.lineTo(SkIntToScalar(40), SkIntToScalar(80));
125 path.lineTo(SkIntToScalar(80), SkIntToScalar(50));
senorblancod6ed19c2015-02-26 06:58:17 -0800126 canvas->drawPath(path, paint);
127 canvas->restore();
128}
129
130// Square polygon with a square hole.
131void test_hole(SkCanvas* canvas, const SkPaint& paint) {
132 SkPath path;
133 canvas->save();
134 canvas->translate(200, 100);
135 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
136 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
137 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
138 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
139 path.moveTo(SkIntToScalar(30), SkIntToScalar(30));
140 path.lineTo(SkIntToScalar(30), SkIntToScalar(70));
141 path.lineTo(SkIntToScalar(70), SkIntToScalar(70));
142 path.lineTo(SkIntToScalar(70), SkIntToScalar(30));
143 canvas->drawPath(path, paint);
144 canvas->restore();
145}
146
147// Star test (self-intersecting)
148void test_star(SkCanvas* canvas, const SkPaint& paint) {
149 SkPath path;
150 canvas->save();
151 canvas->translate(300, 100);
152 path.moveTo(30, 20);
153 path.lineTo(50, 80);
154 path.lineTo(70, 20);
155 path.lineTo(20, 57);
156 path.lineTo(80, 57);
157 path.close();
158 canvas->drawPath(path, paint);
159 canvas->restore();
160}
161
162// Stairstep with repeated vert (intersection)
163void test_stairstep(SkCanvas* canvas, const SkPaint& paint) {
164 SkPath path;
165 canvas->save();
166 canvas->translate(0, 200);
167 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
168 path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
169 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
170 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
171 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
172 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
173 canvas->drawPath(path, paint);
174 canvas->restore();
175}
176
177void test_stairstep2(SkCanvas* canvas, const SkPaint& paint) {
178 SkPath path;
179 canvas->save();
180 canvas->translate(100, 200);
181 path.moveTo(20, 60);
182 path.lineTo(35, 80);
183 path.lineTo(50, 60);
184 path.lineTo(65, 80);
185 path.lineTo(80, 60);
186 canvas->drawPath(path, paint);
187 canvas->restore();
188}
189
190// Overlapping segments
191void test_overlapping(SkCanvas* canvas, const SkPaint& paint) {
192 SkPath path;
193 canvas->save();
194 canvas->translate(200, 200);
195 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
196 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
197 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
198 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
199 canvas->drawPath(path, paint);
200 canvas->restore();
201}
202
senorblanco531237e2016-06-02 11:36:48 -0700203// Two "island" triangles inside a containing rect.
204// This exercises the partnering code in the tessellator.
205void test_partners(SkCanvas* canvas, const SkPaint& paint) {
206 SkPath path;
207 canvas->save();
208 canvas->translate(300, 200);
209 path.moveTo(20, 80);
210 path.lineTo(80, 80);
211 path.lineTo(80, 20);
212 path.lineTo(20, 20);
213 path.moveTo(30, 30);
214 path.lineTo(45, 50);
215 path.lineTo(30, 70);
216 path.moveTo(70, 30);
217 path.lineTo(70, 70);
218 path.lineTo(55, 50);
219 canvas->drawPath(path, paint);
220 canvas->restore();
221}
222
senorblancod6ed19c2015-02-26 06:58:17 -0800223// Monotone test 1 (point in the middle)
224void test_monotone_1(SkCanvas* canvas, const SkPaint& paint) {
225 SkPath path;
226 canvas->save();
227 canvas->translate(0, 300);
228 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
229 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
230 SkIntToScalar(80), SkIntToScalar(50));
231 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
232 SkIntToScalar(20), SkIntToScalar(80));
233 canvas->drawPath(path, paint);
234 canvas->restore();
235}
236
237// Monotone test 2 (point at the top)
238void test_monotone_2(SkCanvas* canvas, const SkPaint& paint) {
239 SkPath path;
240 canvas->save();
241 canvas->translate(100, 300);
242 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
243 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
244 path.quadTo(SkIntToScalar(20), SkIntToScalar(20),
245 SkIntToScalar(20), SkIntToScalar(80));
246 canvas->drawPath(path, paint);
247 canvas->restore();
248}
249
250// Monotone test 3 (point at the bottom)
251void test_monotone_3(SkCanvas* canvas, const SkPaint& paint) {
252 SkPath path;
253 canvas->save();
254 canvas->translate(200, 300);
255 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
256 path.lineTo(SkIntToScalar(80), SkIntToScalar(70));
257 path.quadTo(SkIntToScalar(20), SkIntToScalar(80),
258 SkIntToScalar(20), SkIntToScalar(20));
259 canvas->drawPath(path, paint);
260 canvas->restore();
261}
262
263// Monotone test 4 (merging of two monotones)
264void test_monotone_4(SkCanvas* canvas, const SkPaint& paint) {
265 SkPath path;
266 canvas->save();
267 canvas->translate(300, 300);
268 path.moveTo(80, 25);
269 path.lineTo(50, 39);
270 path.lineTo(20, 25);
271 path.lineTo(40, 45);
272 path.lineTo(70, 50);
273 path.lineTo(80, 80);
274 canvas->drawPath(path, paint);
275 canvas->restore();
276}
277
278// Monotone test 5 (aborted merging of two monotones)
279void test_monotone_5(SkCanvas* canvas, const SkPaint& paint) {
280 SkPath path;
281 canvas->save();
282 canvas->translate(0, 400);
283 path.moveTo(50, 20);
284 path.lineTo(80, 80);
285 path.lineTo(50, 50);
286 path.lineTo(20, 80);
287 canvas->drawPath(path, paint);
288 canvas->restore();
289}
290// Degenerate intersection test
291void test_degenerate(SkCanvas* canvas, const SkPaint& paint) {
292 SkPath path;
293 canvas->save();
294 canvas->translate(100, 400);
295 path.moveTo(50, 20);
296 path.lineTo(70, 30);
297 path.lineTo(20, 50);
298 path.moveTo(50, 20);
299 path.lineTo(80, 80);
300 path.lineTo(50, 80);
301 canvas->drawPath(path, paint);
302 canvas->restore();
303}
304// Two triangles with a coincident edge.
305void test_coincident_edge(SkCanvas* canvas, const SkPaint& paint) {
306 SkPath path;
307 canvas->save();
308 canvas->translate(200, 400);
309
310 path.moveTo(80, 20);
311 path.lineTo(80, 80);
312 path.lineTo(20, 80);
313
314 path.moveTo(20, 20);
315 path.lineTo(80, 80);
316 path.lineTo(20, 80);
317
318 canvas->drawPath(path, paint);
319 canvas->restore();
320}
321// Bowtie with a coincident triangle (one triangle vertex coincident with the
322// bowtie's intersection).
323void test_bowtie_coincident_triangle(SkCanvas* canvas, const SkPaint& paint) {
324 SkPath path;
325 canvas->save();
326 canvas->translate(300, 400);
327 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
328 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
329 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
330 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
331 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
332 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
333 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
334 canvas->drawPath(path, paint);
335 canvas->restore();
336}
337
338// Coincident edges (big ones first, coincident vert on top).
339void test_coincident_edges_1(SkCanvas* canvas, const SkPaint& paint) {
340 SkPath path;
341 canvas->save();
342 canvas->translate(0, 500);
343 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
344 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
345 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
346 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
347 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
348 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
349 canvas->drawPath(path, paint);
350 canvas->restore();
351}
352// Coincident edges (small ones first, coincident vert on top).
353void test_coincident_edges_2(SkCanvas* canvas, const SkPaint& paint) {
354 SkPath path;
355 canvas->save();
356 canvas->translate(100, 500);
357 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
358 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
359 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
360 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
361 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
362 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
363 canvas->drawPath(path, paint);
364 canvas->restore();
365}
366// Coincident edges (small ones first, coincident vert on bottom).
367void test_coincident_edges_3(SkCanvas* canvas, const SkPaint& paint) {
368 SkPath path;
369 canvas->save();
370 canvas->translate(200, 500);
371 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
372 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
373 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
374 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
375 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
376 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
377 canvas->drawPath(path, paint);
378 canvas->restore();
379}
380// Coincident edges (big ones first, coincident vert on bottom).
381void test_coincident_edges_4(SkCanvas* canvas, const SkPaint& paint) {
382 SkPath path;
383 canvas->save();
384 canvas->translate(300, 500);
385 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
386 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
387 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
388 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
389 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
390 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
391 canvas->drawPath(path, paint);
392 canvas->restore();
393}
394
395};
396
Stephen White5926f2d2017-02-13 13:55:42 -0500397DEF_SIMPLE_GM(concavepaths, canvas, 500, 600) {
Stephen White930f69e2017-01-12 17:15:50 -0500398 SkPaint paint;
senorblancod6ed19c2015-02-26 06:58:17 -0800399
Stephen White930f69e2017-01-12 17:15:50 -0500400 paint.setAntiAlias(true);
401 paint.setStyle(SkPaint::kFill_Style);
senorblancod6ed19c2015-02-26 06:58:17 -0800402
Stephen White930f69e2017-01-12 17:15:50 -0500403 test_concave(canvas, paint);
404 test_reverse_concave(canvas, paint);
405 test_bowtie(canvas, paint);
406 test_fake_bowtie(canvas, paint);
Stephen White5926f2d2017-02-13 13:55:42 -0500407 test_intruding_vertex(canvas, paint);
Stephen White930f69e2017-01-12 17:15:50 -0500408 test_fish(canvas, paint);
409 test_fast_forward(canvas, paint);
410 test_hole(canvas, paint);
411 test_star(canvas, paint);
Stephen White5926f2d2017-02-13 13:55:42 -0500412 test_inversion_repeat_vertex(canvas, paint);
Stephen White930f69e2017-01-12 17:15:50 -0500413 test_stairstep(canvas, paint);
414 test_stairstep2(canvas, paint);
415 test_overlapping(canvas, paint);
416 test_partners(canvas, paint);
417 test_monotone_1(canvas, paint);
418 test_monotone_2(canvas, paint);
419 test_monotone_3(canvas, paint);
420 test_monotone_4(canvas, paint);
421 test_monotone_5(canvas, paint);
422 test_degenerate(canvas, paint);
423 test_coincident_edge(canvas, paint);
424 test_bowtie_coincident_triangle(canvas, paint);
425 test_coincident_edges_1(canvas, paint);
426 test_coincident_edges_2(canvas, paint);
427 test_coincident_edges_3(canvas, paint);
428 test_coincident_edges_4(canvas, paint);
429}