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