blob: c68265b99fb5e5fd78bc2b59227f6261848ae697 [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
Stephen White2f4686f2017-01-03 16:20:01 -050083// Overlapping "Fast-forward" icon: tests coincidence of inner and outer
84// vertices generated by intersection.
85void test_fast_forward(SkCanvas* canvas, const SkPaint& paint) {
senorblancod6ed19c2015-02-26 06:58:17 -080086 SkPath path;
87 canvas->save();
88 canvas->translate(100, 100);
89 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
Stephen White2f4686f2017-01-03 16:20:01 -050090 path.lineTo(SkIntToScalar(60), SkIntToScalar(50));
91 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
92 path.moveTo(SkIntToScalar(40), SkIntToScalar(20));
93 path.lineTo(SkIntToScalar(40), SkIntToScalar(80));
94 path.lineTo(SkIntToScalar(80), SkIntToScalar(50));
senorblancod6ed19c2015-02-26 06:58:17 -080095 canvas->drawPath(path, paint);
96 canvas->restore();
97}
98
99// Square polygon with a square hole.
100void test_hole(SkCanvas* canvas, const SkPaint& paint) {
101 SkPath path;
102 canvas->save();
103 canvas->translate(200, 100);
104 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
105 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
106 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
107 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
108 path.moveTo(SkIntToScalar(30), SkIntToScalar(30));
109 path.lineTo(SkIntToScalar(30), SkIntToScalar(70));
110 path.lineTo(SkIntToScalar(70), SkIntToScalar(70));
111 path.lineTo(SkIntToScalar(70), SkIntToScalar(30));
112 canvas->drawPath(path, paint);
113 canvas->restore();
114}
115
116// Star test (self-intersecting)
117void test_star(SkCanvas* canvas, const SkPaint& paint) {
118 SkPath path;
119 canvas->save();
120 canvas->translate(300, 100);
121 path.moveTo(30, 20);
122 path.lineTo(50, 80);
123 path.lineTo(70, 20);
124 path.lineTo(20, 57);
125 path.lineTo(80, 57);
126 path.close();
127 canvas->drawPath(path, paint);
128 canvas->restore();
129}
130
131// Stairstep with repeated vert (intersection)
132void test_stairstep(SkCanvas* canvas, const SkPaint& paint) {
133 SkPath path;
134 canvas->save();
135 canvas->translate(0, 200);
136 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
137 path.lineTo(SkIntToScalar(50), SkIntToScalar(20));
138 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
139 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
140 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
141 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
142 canvas->drawPath(path, paint);
143 canvas->restore();
144}
145
146void test_stairstep2(SkCanvas* canvas, const SkPaint& paint) {
147 SkPath path;
148 canvas->save();
149 canvas->translate(100, 200);
150 path.moveTo(20, 60);
151 path.lineTo(35, 80);
152 path.lineTo(50, 60);
153 path.lineTo(65, 80);
154 path.lineTo(80, 60);
155 canvas->drawPath(path, paint);
156 canvas->restore();
157}
158
159// Overlapping segments
160void test_overlapping(SkCanvas* canvas, const SkPaint& paint) {
161 SkPath path;
162 canvas->save();
163 canvas->translate(200, 200);
164 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
165 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
166 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
167 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
168 canvas->drawPath(path, paint);
169 canvas->restore();
170}
171
senorblanco531237e2016-06-02 11:36:48 -0700172// Two "island" triangles inside a containing rect.
173// This exercises the partnering code in the tessellator.
174void test_partners(SkCanvas* canvas, const SkPaint& paint) {
175 SkPath path;
176 canvas->save();
177 canvas->translate(300, 200);
178 path.moveTo(20, 80);
179 path.lineTo(80, 80);
180 path.lineTo(80, 20);
181 path.lineTo(20, 20);
182 path.moveTo(30, 30);
183 path.lineTo(45, 50);
184 path.lineTo(30, 70);
185 path.moveTo(70, 30);
186 path.lineTo(70, 70);
187 path.lineTo(55, 50);
188 canvas->drawPath(path, paint);
189 canvas->restore();
190}
191
senorblancod6ed19c2015-02-26 06:58:17 -0800192// Monotone test 1 (point in the middle)
193void test_monotone_1(SkCanvas* canvas, const SkPaint& paint) {
194 SkPath path;
195 canvas->save();
196 canvas->translate(0, 300);
197 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
198 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
199 SkIntToScalar(80), SkIntToScalar(50));
200 path.quadTo(SkIntToScalar(20), SkIntToScalar(50),
201 SkIntToScalar(20), SkIntToScalar(80));
202 canvas->drawPath(path, paint);
203 canvas->restore();
204}
205
206// Monotone test 2 (point at the top)
207void test_monotone_2(SkCanvas* canvas, const SkPaint& paint) {
208 SkPath path;
209 canvas->save();
210 canvas->translate(100, 300);
211 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
212 path.lineTo(SkIntToScalar(80), SkIntToScalar(30));
213 path.quadTo(SkIntToScalar(20), SkIntToScalar(20),
214 SkIntToScalar(20), SkIntToScalar(80));
215 canvas->drawPath(path, paint);
216 canvas->restore();
217}
218
219// Monotone test 3 (point at the bottom)
220void test_monotone_3(SkCanvas* canvas, const SkPaint& paint) {
221 SkPath path;
222 canvas->save();
223 canvas->translate(200, 300);
224 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
225 path.lineTo(SkIntToScalar(80), SkIntToScalar(70));
226 path.quadTo(SkIntToScalar(20), SkIntToScalar(80),
227 SkIntToScalar(20), SkIntToScalar(20));
228 canvas->drawPath(path, paint);
229 canvas->restore();
230}
231
232// Monotone test 4 (merging of two monotones)
233void test_monotone_4(SkCanvas* canvas, const SkPaint& paint) {
234 SkPath path;
235 canvas->save();
236 canvas->translate(300, 300);
237 path.moveTo(80, 25);
238 path.lineTo(50, 39);
239 path.lineTo(20, 25);
240 path.lineTo(40, 45);
241 path.lineTo(70, 50);
242 path.lineTo(80, 80);
243 canvas->drawPath(path, paint);
244 canvas->restore();
245}
246
247// Monotone test 5 (aborted merging of two monotones)
248void test_monotone_5(SkCanvas* canvas, const SkPaint& paint) {
249 SkPath path;
250 canvas->save();
251 canvas->translate(0, 400);
252 path.moveTo(50, 20);
253 path.lineTo(80, 80);
254 path.lineTo(50, 50);
255 path.lineTo(20, 80);
256 canvas->drawPath(path, paint);
257 canvas->restore();
258}
259// Degenerate intersection test
260void test_degenerate(SkCanvas* canvas, const SkPaint& paint) {
261 SkPath path;
262 canvas->save();
263 canvas->translate(100, 400);
264 path.moveTo(50, 20);
265 path.lineTo(70, 30);
266 path.lineTo(20, 50);
267 path.moveTo(50, 20);
268 path.lineTo(80, 80);
269 path.lineTo(50, 80);
270 canvas->drawPath(path, paint);
271 canvas->restore();
272}
273// Two triangles with a coincident edge.
274void test_coincident_edge(SkCanvas* canvas, const SkPaint& paint) {
275 SkPath path;
276 canvas->save();
277 canvas->translate(200, 400);
278
279 path.moveTo(80, 20);
280 path.lineTo(80, 80);
281 path.lineTo(20, 80);
282
283 path.moveTo(20, 20);
284 path.lineTo(80, 80);
285 path.lineTo(20, 80);
286
287 canvas->drawPath(path, paint);
288 canvas->restore();
289}
290// Bowtie with a coincident triangle (one triangle vertex coincident with the
291// bowtie's intersection).
292void test_bowtie_coincident_triangle(SkCanvas* canvas, const SkPaint& paint) {
293 SkPath path;
294 canvas->save();
295 canvas->translate(300, 400);
296 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
297 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
298 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
299 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
300 path.moveTo(SkIntToScalar(50), SkIntToScalar(50));
301 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
302 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
303 canvas->drawPath(path, 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) {
309 SkPath path;
310 canvas->save();
311 canvas->translate(0, 500);
312 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
313 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
314 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
315 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
316 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
317 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
318 canvas->drawPath(path, 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) {
323 SkPath path;
324 canvas->save();
325 canvas->translate(100, 500);
326 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
327 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
328 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
329 path.moveTo(SkIntToScalar(20), SkIntToScalar(20));
330 path.lineTo(SkIntToScalar(80), SkIntToScalar(80));
331 path.lineTo(SkIntToScalar(20), SkIntToScalar(80));
332 canvas->drawPath(path, 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) {
337 SkPath path;
338 canvas->save();
339 canvas->translate(200, 500);
340 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
341 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
342 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
343 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
344 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
345 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
346 canvas->drawPath(path, 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) {
351 SkPath path;
352 canvas->save();
353 canvas->translate(300, 500);
354 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
355 path.lineTo(SkIntToScalar(20), SkIntToScalar(20));
356 path.lineTo(SkIntToScalar(80), SkIntToScalar(20));
357 path.moveTo(SkIntToScalar(20), SkIntToScalar(80));
358 path.lineTo(SkIntToScalar(20), SkIntToScalar(50));
359 path.lineTo(SkIntToScalar(50), SkIntToScalar(50));
360 canvas->drawPath(path, paint);
361 canvas->restore();
362}
363
364};
365
366class ConcavePathsGM : public skiagm::GM {
367public:
368 ConcavePathsGM() {}
369
370protected:
mtklein36352bf2015-03-25 18:17:31 -0700371 SkString onShortName() override {
senorblancod6ed19c2015-02-26 06:58:17 -0800372 return SkString("concavepaths");
373 }
374
mtklein36352bf2015-03-25 18:17:31 -0700375 SkISize onISize() override {
senorblancod6ed19c2015-02-26 06:58:17 -0800376 return SkISize::Make(WIDTH, HEIGHT);
377 }
378
mtklein36352bf2015-03-25 18:17:31 -0700379 void onDraw(SkCanvas* canvas) override {
senorblancod6ed19c2015-02-26 06:58:17 -0800380 SkPaint paint;
381
382 paint.setAntiAlias(true);
383 paint.setStyle(SkPaint::kFill_Style);
384
385 test_concave(canvas, paint);
386 test_reverse_concave(canvas, paint);
387 test_bowtie(canvas, paint);
388 test_fake_bowtie(canvas, paint);
389 test_fish(canvas, paint);
Stephen White2f4686f2017-01-03 16:20:01 -0500390 test_fast_forward(canvas, paint);
senorblancod6ed19c2015-02-26 06:58:17 -0800391 test_hole(canvas, paint);
392 test_star(canvas, paint);
393 test_stairstep(canvas, paint);
394 test_stairstep2(canvas, paint);
395 test_overlapping(canvas, paint);
senorblanco531237e2016-06-02 11:36:48 -0700396 test_partners(canvas, paint);
senorblancod6ed19c2015-02-26 06:58:17 -0800397 test_monotone_1(canvas, paint);
398 test_monotone_2(canvas, paint);
399 test_monotone_3(canvas, paint);
400 test_monotone_4(canvas, paint);
401 test_monotone_5(canvas, paint);
402 test_degenerate(canvas, paint);
403 test_coincident_edge(canvas, paint);
404 test_bowtie_coincident_triangle(canvas, paint);
405 test_coincident_edges_1(canvas, paint);
406 test_coincident_edges_2(canvas, paint);
407 test_coincident_edges_3(canvas, paint);
408 test_coincident_edges_4(canvas, paint);
409 }
410
411private:
412 typedef skiagm::GM INHERITED;
413};
414
scroggo96f16e82015-12-10 13:31:59 -0800415DEF_GM( return new ConcavePathsGM; )