blob: c371615f2f68839b00671a5d7afb844f5afb9be5 [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
65// Fish test (intersection/concave)
66void test_fish(SkCanvas* canvas, const SkPaint& paint) {
67 SkPath path;
68 canvas->save();
69 canvas->translate(0, 100);
70 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
71 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
72 path.lineTo(SkIntToScalar(70), SkIntToScalar(50));
73 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
74 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
75 path.lineTo(SkIntToScalar(0), SkIntToScalar(50));
76 canvas->drawPath(path, paint);
77 canvas->restore();
78}
79
Stephen White2f4686f2017-01-03 16:20:01 -050080// Overlapping "Fast-forward" icon: tests coincidence of inner and outer
81// vertices generated by intersection.
82void test_fast_forward(SkCanvas* canvas, const SkPaint& paint) {
senorblancod6ed19c2015-02-26 06:58:17 -080083 SkPath path;
84 canvas->save();
85 canvas->translate(100, 100);
86 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
Stephen White2f4686f2017-01-03 16:20:01 -050087 path.lineTo(SkIntToScalar(60), SkIntToScalar(50));
88 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
89 path.moveTo(SkIntToScalar(40), SkIntToScalar(20));
90 path.lineTo(SkIntToScalar(40), SkIntToScalar(80));
91 path.lineTo(SkIntToScalar(80), SkIntToScalar(50));
senorblancod6ed19c2015-02-26 06:58:17 -080092 canvas->drawPath(path, paint);
93 canvas->restore();
94}
95
96// Square polygon with a square hole.
97void test_hole(SkCanvas* canvas, const SkPaint& paint) {
98 SkPath path;
99 canvas->save();
100 canvas->translate(200, 100);
101 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
102 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
103 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
104 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
105 path.moveTo(SkIntToScalar(30), SkIntToScalar(30));
106 path.lineTo(SkIntToScalar(30), SkIntToScalar(70));
107 path.lineTo(SkIntToScalar(70), SkIntToScalar(70));
108 path.lineTo(SkIntToScalar(70), SkIntToScalar(30));
109 canvas->drawPath(path, paint);
110 canvas->restore();
111}
112
113// Star test (self-intersecting)
114void test_star(SkCanvas* canvas, const SkPaint& paint) {
115 SkPath path;
116 canvas->save();
117 canvas->translate(300, 100);
118 path.moveTo(30, 20);
119 path.lineTo(50, 80);
120 path.lineTo(70, 20);
121 path.lineTo(20, 57);
122 path.lineTo(80, 57);
123 path.close();
124 canvas->drawPath(path, paint);
125 canvas->restore();
126}
127
128// Stairstep with repeated vert (intersection)
129void test_stairstep(SkCanvas* canvas, const SkPaint& paint) {
130 SkPath path;
131 canvas->save();
132 canvas->translate(0, 200);
133 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
134 path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
135 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
136 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
137 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
138 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
139 canvas->drawPath(path, paint);
140 canvas->restore();
141}
142
143void test_stairstep2(SkCanvas* canvas, const SkPaint& paint) {
144 SkPath path;
145 canvas->save();
146 canvas->translate(100, 200);
147 path.moveTo(20, 60);
148 path.lineTo(35, 80);
149 path.lineTo(50, 60);
150 path.lineTo(65, 80);
151 path.lineTo(80, 60);
152 canvas->drawPath(path, paint);
153 canvas->restore();
154}
155
156// Overlapping segments
157void test_overlapping(SkCanvas* canvas, const SkPaint& paint) {
158 SkPath path;
159 canvas->save();
160 canvas->translate(200, 200);
161 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
162 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
163 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
164 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
165 canvas->drawPath(path, paint);
166 canvas->restore();
167}
168
senorblanco531237e2016-06-02 11:36:48 -0700169// Two "island" triangles inside a containing rect.
170// This exercises the partnering code in the tessellator.
171void test_partners(SkCanvas* canvas, const SkPaint& paint) {
172 SkPath path;
173 canvas->save();
174 canvas->translate(300, 200);
175 path.moveTo(20, 80);
176 path.lineTo(80, 80);
177 path.lineTo(80, 20);
178 path.lineTo(20, 20);
179 path.moveTo(30, 30);
180 path.lineTo(45, 50);
181 path.lineTo(30, 70);
182 path.moveTo(70, 30);
183 path.lineTo(70, 70);
184 path.lineTo(55, 50);
185 canvas->drawPath(path, paint);
186 canvas->restore();
187}
188
senorblancod6ed19c2015-02-26 06:58:17 -0800189// Monotone test 1 (point in the middle)
190void test_monotone_1(SkCanvas* canvas, const SkPaint& paint) {
191 SkPath path;
192 canvas->save();
193 canvas->translate(0, 300);
194 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
195 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
196 SkIntToScalar(80), SkIntToScalar(50));
197 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
198 SkIntToScalar(20), SkIntToScalar(80));
199 canvas->drawPath(path, paint);
200 canvas->restore();
201}
202
203// Monotone test 2 (point at the top)
204void test_monotone_2(SkCanvas* canvas, const SkPaint& paint) {
205 SkPath path;
206 canvas->save();
207 canvas->translate(100, 300);
208 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
209 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
210 path.quadTo(SkIntToScalar(20), SkIntToScalar(20),
211 SkIntToScalar(20), SkIntToScalar(80));
212 canvas->drawPath(path, paint);
213 canvas->restore();
214}
215
216// Monotone test 3 (point at the bottom)
217void test_monotone_3(SkCanvas* canvas, const SkPaint& paint) {
218 SkPath path;
219 canvas->save();
220 canvas->translate(200, 300);
221 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
222 path.lineTo(SkIntToScalar(80), SkIntToScalar(70));
223 path.quadTo(SkIntToScalar(20), SkIntToScalar(80),
224 SkIntToScalar(20), SkIntToScalar(20));
225 canvas->drawPath(path, paint);
226 canvas->restore();
227}
228
229// Monotone test 4 (merging of two monotones)
230void test_monotone_4(SkCanvas* canvas, const SkPaint& paint) {
231 SkPath path;
232 canvas->save();
233 canvas->translate(300, 300);
234 path.moveTo(80, 25);
235 path.lineTo(50, 39);
236 path.lineTo(20, 25);
237 path.lineTo(40, 45);
238 path.lineTo(70, 50);
239 path.lineTo(80, 80);
240 canvas->drawPath(path, paint);
241 canvas->restore();
242}
243
244// Monotone test 5 (aborted merging of two monotones)
245void test_monotone_5(SkCanvas* canvas, const SkPaint& paint) {
246 SkPath path;
247 canvas->save();
248 canvas->translate(0, 400);
249 path.moveTo(50, 20);
250 path.lineTo(80, 80);
251 path.lineTo(50, 50);
252 path.lineTo(20, 80);
253 canvas->drawPath(path, paint);
254 canvas->restore();
255}
256// Degenerate intersection test
257void test_degenerate(SkCanvas* canvas, const SkPaint& paint) {
258 SkPath path;
259 canvas->save();
260 canvas->translate(100, 400);
261 path.moveTo(50, 20);
262 path.lineTo(70, 30);
263 path.lineTo(20, 50);
264 path.moveTo(50, 20);
265 path.lineTo(80, 80);
266 path.lineTo(50, 80);
267 canvas->drawPath(path, paint);
268 canvas->restore();
269}
270// Two triangles with a coincident edge.
271void test_coincident_edge(SkCanvas* canvas, const SkPaint& paint) {
272 SkPath path;
273 canvas->save();
274 canvas->translate(200, 400);
275
276 path.moveTo(80, 20);
277 path.lineTo(80, 80);
278 path.lineTo(20, 80);
279
280 path.moveTo(20, 20);
281 path.lineTo(80, 80);
282 path.lineTo(20, 80);
283
284 canvas->drawPath(path, paint);
285 canvas->restore();
286}
287// Bowtie with a coincident triangle (one triangle vertex coincident with the
288// bowtie's intersection).
289void test_bowtie_coincident_triangle(SkCanvas* canvas, const SkPaint& paint) {
290 SkPath path;
291 canvas->save();
292 canvas->translate(300, 400);
293 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
294 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
295 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
296 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
297 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
298 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
299 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
300 canvas->drawPath(path, paint);
301 canvas->restore();
302}
303
304// Coincident edges (big ones first, coincident vert on top).
305void test_coincident_edges_1(SkCanvas* canvas, const SkPaint& paint) {
306 SkPath path;
307 canvas->save();
308 canvas->translate(0, 500);
309 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
310 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
311 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
312 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
313 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
314 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
315 canvas->drawPath(path, paint);
316 canvas->restore();
317}
318// Coincident edges (small ones first, coincident vert on top).
319void test_coincident_edges_2(SkCanvas* canvas, const SkPaint& paint) {
320 SkPath path;
321 canvas->save();
322 canvas->translate(100, 500);
323 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
324 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
325 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
326 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
327 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
328 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
329 canvas->drawPath(path, paint);
330 canvas->restore();
331}
332// Coincident edges (small ones first, coincident vert on bottom).
333void test_coincident_edges_3(SkCanvas* canvas, const SkPaint& paint) {
334 SkPath path;
335 canvas->save();
336 canvas->translate(200, 500);
337 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
338 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
339 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
340 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
341 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
342 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
343 canvas->drawPath(path, paint);
344 canvas->restore();
345}
346// Coincident edges (big ones first, coincident vert on bottom).
347void test_coincident_edges_4(SkCanvas* canvas, const SkPaint& paint) {
348 SkPath path;
349 canvas->save();
350 canvas->translate(300, 500);
351 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
352 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
353 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
354 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
355 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
356 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
357 canvas->drawPath(path, paint);
358 canvas->restore();
359}
360
361};
362
Stephen White930f69e2017-01-12 17:15:50 -0500363DEF_SIMPLE_GM(concavepaths, canvas, 400, 600) {
364 SkPaint paint;
senorblancod6ed19c2015-02-26 06:58:17 -0800365
Stephen White930f69e2017-01-12 17:15:50 -0500366 paint.setAntiAlias(true);
367 paint.setStyle(SkPaint::kFill_Style);
senorblancod6ed19c2015-02-26 06:58:17 -0800368
Stephen White930f69e2017-01-12 17:15:50 -0500369 test_concave(canvas, paint);
370 test_reverse_concave(canvas, paint);
371 test_bowtie(canvas, paint);
372 test_fake_bowtie(canvas, paint);
373 test_fish(canvas, paint);
374 test_fast_forward(canvas, paint);
375 test_hole(canvas, paint);
376 test_star(canvas, paint);
377 test_stairstep(canvas, paint);
378 test_stairstep2(canvas, paint);
379 test_overlapping(canvas, paint);
380 test_partners(canvas, paint);
381 test_monotone_1(canvas, paint);
382 test_monotone_2(canvas, paint);
383 test_monotone_3(canvas, paint);
384 test_monotone_4(canvas, paint);
385 test_monotone_5(canvas, paint);
386 test_degenerate(canvas, paint);
387 test_coincident_edge(canvas, paint);
388 test_bowtie_coincident_triangle(canvas, paint);
389 test_coincident_edges_1(canvas, paint);
390 test_coincident_edges_2(canvas, paint);
391 test_coincident_edges_3(canvas, paint);
392 test_coincident_edges_4(canvas, paint);
393}