• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #include "SkPath.h"
11 
12 #define WIDTH 400
13 #define HEIGHT 600
14 
15 namespace {
16 // Concave test
test_concave(SkCanvas * canvas,const SkPaint & paint)17 void 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
test_reverse_concave(SkCanvas * canvas,const SkPaint & paint)28 void 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)
test_bowtie(SkCanvas * canvas,const SkPaint & paint)41 void 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)
test_fake_bowtie(SkCanvas * canvas,const SkPaint & paint)54 void 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)
test_fish(SkCanvas * canvas,const SkPaint & paint)69 void 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
test_collinear_edges(SkCanvas * canvas,const SkPaint & paint)84 void 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.
test_hole(SkCanvas * canvas,const SkPaint & paint)97 void 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)
test_star(SkCanvas * canvas,const SkPaint & paint)114 void 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)
test_stairstep(SkCanvas * canvas,const SkPaint & paint)129 void 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 
test_stairstep2(SkCanvas * canvas,const SkPaint & paint)143 void 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
test_overlapping(SkCanvas * canvas,const SkPaint & paint)157 void 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)
test_monotone_1(SkCanvas * canvas,const SkPaint & paint)170 void 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)
test_monotone_2(SkCanvas * canvas,const SkPaint & paint)184 void 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)
test_monotone_3(SkCanvas * canvas,const SkPaint & paint)197 void 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)
test_monotone_4(SkCanvas * canvas,const SkPaint & paint)210 void 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)
test_monotone_5(SkCanvas * canvas,const SkPaint & paint)225 void 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
test_degenerate(SkCanvas * canvas,const SkPaint & paint)237 void 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.
test_coincident_edge(SkCanvas * canvas,const SkPaint & paint)251 void 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).
test_bowtie_coincident_triangle(SkCanvas * canvas,const SkPaint & paint)269 void 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).
test_coincident_edges_1(SkCanvas * canvas,const SkPaint & paint)285 void 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).
test_coincident_edges_2(SkCanvas * canvas,const SkPaint & paint)299 void 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).
test_coincident_edges_3(SkCanvas * canvas,const SkPaint & paint)313 void 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).
test_coincident_edges_4(SkCanvas * canvas,const SkPaint & paint)327 void 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 
343 class ConcavePathsGM : public skiagm::GM {
344 public:
ConcavePathsGM()345     ConcavePathsGM() {}
346 
347 protected:
onShortName()348     SkString onShortName() override {
349         return SkString("concavepaths");
350     }
351 
onISize()352     SkISize onISize() override {
353         return SkISize::Make(WIDTH, HEIGHT);
354     }
355 
onDraw(SkCanvas * canvas)356     void onDraw(SkCanvas* canvas) override {
357         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 
387 private:
388     typedef skiagm::GM INHERITED;
389 };
390 
391 DEF_GM( return new ConcavePathsGM; )
392