blob: 37635f8b67f6ddaf1fbd07f2d12291703df2906e [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
12#define WIDTH 400
13#define HEIGHT 600
14
15namespace {
16// Concave test
17void test_concave(SkCanvas* canvas, const SkPaint& paint) {
18 SkPath path;
19 canvas->translate(0, 0);
20 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
21 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
22 path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
23 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
24 canvas->drawPath(path, paint);
25}
26
27// Reverse concave test
28void test_reverse_concave(SkCanvas* canvas, const SkPaint& paint) {
29 SkPath path;
30 canvas->save();
31 canvas->translate(100, 0);
32 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
33 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
34 path.lineTo(SkIntToScalar(30), SkIntToScalar(30));
35 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
36 canvas->drawPath(path, paint);
37 canvas->restore();
38}
39
40// Bowtie (intersection)
41void test_bowtie(SkCanvas* canvas, const SkPaint& paint) {
42 SkPath path;
43 canvas->save();
44 canvas->translate(200, 0);
45 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
46 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
47 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
48 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
49 canvas->drawPath(path, paint);
50 canvas->restore();
51}
52
53// "fake" bowtie (concave, but no intersection)
54void test_fake_bowtie(SkCanvas* canvas, const SkPaint& paint) {
55 SkPath path;
56 canvas->save();
57 canvas->translate(300, 0);
58 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
59 path.lineTo(SkIntToScalar(50), SkIntToScalar(40));
60 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
61 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
62 path.lineTo(SkIntToScalar(50), SkIntToScalar(60));
63 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
64 canvas->drawPath(path, paint);
65 canvas->restore();
66}
67
68// Fish test (intersection/concave)
69void test_fish(SkCanvas* canvas, const SkPaint& paint) {
70 SkPath path;
71 canvas->save();
72 canvas->translate(0, 100);
73 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
74 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
75 path.lineTo(SkIntToScalar(70), SkIntToScalar(50));
76 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
77 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
78 path.lineTo(SkIntToScalar(0), SkIntToScalar(50));
79 canvas->drawPath(path, paint);
80 canvas->restore();
81}
82
83// Collinear edges
84void test_collinear_edges(SkCanvas* canvas, const SkPaint& paint) {
85 SkPath path;
86 canvas->save();
87 canvas->translate(100, 100);
88 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
89 path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
90 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
91 path.lineTo(SkIntToScalar(50), SkIntToScalar(80));
92 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
169// Monotone test 1 (point in the middle)
170void test_monotone_1(SkCanvas* canvas, const SkPaint& paint) {
171 SkPath path;
172 canvas->save();
173 canvas->translate(0, 300);
174 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
175 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
176 SkIntToScalar(80), SkIntToScalar(50));
177 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
178 SkIntToScalar(20), SkIntToScalar(80));
179 canvas->drawPath(path, paint);
180 canvas->restore();
181}
182
183// Monotone test 2 (point at the top)
184void test_monotone_2(SkCanvas* canvas, const SkPaint& paint) {
185 SkPath path;
186 canvas->save();
187 canvas->translate(100, 300);
188 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
189 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
190 path.quadTo(SkIntToScalar(20), SkIntToScalar(20),
191 SkIntToScalar(20), SkIntToScalar(80));
192 canvas->drawPath(path, paint);
193 canvas->restore();
194}
195
196// Monotone test 3 (point at the bottom)
197void test_monotone_3(SkCanvas* canvas, const SkPaint& paint) {
198 SkPath path;
199 canvas->save();
200 canvas->translate(200, 300);
201 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
202 path.lineTo(SkIntToScalar(80), SkIntToScalar(70));
203 path.quadTo(SkIntToScalar(20), SkIntToScalar(80),
204 SkIntToScalar(20), SkIntToScalar(20));
205 canvas->drawPath(path, paint);
206 canvas->restore();
207}
208
209// Monotone test 4 (merging of two monotones)
210void test_monotone_4(SkCanvas* canvas, const SkPaint& paint) {
211 SkPath path;
212 canvas->save();
213 canvas->translate(300, 300);
214 path.moveTo(80, 25);
215 path.lineTo(50, 39);
216 path.lineTo(20, 25);
217 path.lineTo(40, 45);
218 path.lineTo(70, 50);
219 path.lineTo(80, 80);
220 canvas->drawPath(path, paint);
221 canvas->restore();
222}
223
224// Monotone test 5 (aborted merging of two monotones)
225void test_monotone_5(SkCanvas* canvas, const SkPaint& paint) {
226 SkPath path;
227 canvas->save();
228 canvas->translate(0, 400);
229 path.moveTo(50, 20);
230 path.lineTo(80, 80);
231 path.lineTo(50, 50);
232 path.lineTo(20, 80);
233 canvas->drawPath(path, paint);
234 canvas->restore();
235}
236// Degenerate intersection test
237void test_degenerate(SkCanvas* canvas, const SkPaint& paint) {
238 SkPath path;
239 canvas->save();
240 canvas->translate(100, 400);
241 path.moveTo(50, 20);
242 path.lineTo(70, 30);
243 path.lineTo(20, 50);
244 path.moveTo(50, 20);
245 path.lineTo(80, 80);
246 path.lineTo(50, 80);
247 canvas->drawPath(path, paint);
248 canvas->restore();
249}
250// Two triangles with a coincident edge.
251void test_coincident_edge(SkCanvas* canvas, const SkPaint& paint) {
252 SkPath path;
253 canvas->save();
254 canvas->translate(200, 400);
255
256 path.moveTo(80, 20);
257 path.lineTo(80, 80);
258 path.lineTo(20, 80);
259
260 path.moveTo(20, 20);
261 path.lineTo(80, 80);
262 path.lineTo(20, 80);
263
264 canvas->drawPath(path, paint);
265 canvas->restore();
266}
267// Bowtie with a coincident triangle (one triangle vertex coincident with the
268// bowtie's intersection).
269void test_bowtie_coincident_triangle(SkCanvas* canvas, const SkPaint& paint) {
270 SkPath path;
271 canvas->save();
272 canvas->translate(300, 400);
273 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
274 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
275 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
276 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
277 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
278 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
279 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
280 canvas->drawPath(path, paint);
281 canvas->restore();
282}
283
284// Coincident edges (big ones first, coincident vert on top).
285void test_coincident_edges_1(SkCanvas* canvas, const SkPaint& paint) {
286 SkPath path;
287 canvas->save();
288 canvas->translate(0, 500);
289 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
290 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
291 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
292 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
293 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
294 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
295 canvas->drawPath(path, paint);
296 canvas->restore();
297}
298// Coincident edges (small ones first, coincident vert on top).
299void test_coincident_edges_2(SkCanvas* canvas, const SkPaint& paint) {
300 SkPath path;
301 canvas->save();
302 canvas->translate(100, 500);
303 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
304 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
305 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
306 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
307 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
308 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
309 canvas->drawPath(path, paint);
310 canvas->restore();
311}
312// Coincident edges (small ones first, coincident vert on bottom).
313void test_coincident_edges_3(SkCanvas* canvas, const SkPaint& paint) {
314 SkPath path;
315 canvas->save();
316 canvas->translate(200, 500);
317 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
318 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
319 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
320 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
321 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
322 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
323 canvas->drawPath(path, paint);
324 canvas->restore();
325}
326// Coincident edges (big ones first, coincident vert on bottom).
327void test_coincident_edges_4(SkCanvas* canvas, const SkPaint& paint) {
328 SkPath path;
329 canvas->save();
330 canvas->translate(300, 500);
331 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
332 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
333 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
334 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
335 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
336 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
337 canvas->drawPath(path, paint);
338 canvas->restore();
339}
340
341};
342
343class ConcavePathsGM : public skiagm::GM {
344public:
345 ConcavePathsGM() {}
346
347protected:
mtklein36352bf2015-03-25 18:17:31 -0700348 SkString onShortName() override {
senorblancod6ed19c2015-02-26 06:58:17 -0800349 return SkString("concavepaths");
350 }
351
mtklein36352bf2015-03-25 18:17:31 -0700352 SkISize onISize() override {
senorblancod6ed19c2015-02-26 06:58:17 -0800353 return SkISize::Make(WIDTH, HEIGHT);
354 }
355
mtklein36352bf2015-03-25 18:17:31 -0700356 void onDraw(SkCanvas* canvas) override {
senorblancod6ed19c2015-02-26 06:58:17 -0800357 SkPaint paint;
358
359 paint.setAntiAlias(true);
360 paint.setStyle(SkPaint::kFill_Style);
361
362 test_concave(canvas, paint);
363 test_reverse_concave(canvas, paint);
364 test_bowtie(canvas, paint);
365 test_fake_bowtie(canvas, paint);
366 test_fish(canvas, paint);
367 test_collinear_edges(canvas, paint);
368 test_hole(canvas, paint);
369 test_star(canvas, paint);
370 test_stairstep(canvas, paint);
371 test_stairstep2(canvas, paint);
372 test_overlapping(canvas, paint);
373 test_monotone_1(canvas, paint);
374 test_monotone_2(canvas, paint);
375 test_monotone_3(canvas, paint);
376 test_monotone_4(canvas, paint);
377 test_monotone_5(canvas, paint);
378 test_degenerate(canvas, paint);
379 test_coincident_edge(canvas, paint);
380 test_bowtie_coincident_triangle(canvas, paint);
381 test_coincident_edges_1(canvas, paint);
382 test_coincident_edges_2(canvas, paint);
383 test_coincident_edges_3(canvas, paint);
384 test_coincident_edges_4(canvas, paint);
385 }
386
387private:
388 typedef skiagm::GM INHERITED;
389};
390
391static skiagm::GM* F0(void*) { return new ConcavePathsGM; }
392static skiagm::GMRegistry R0(F0);