• Home
  • History
  • Annotate
  • 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 
11 #define WIDTH 400
12 #define HEIGHT 600
13 
14 namespace {
15 // Concave test
test_concave(SkCanvas * canvas,const SkPaint & paint)16 void 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
test_reverse_concave(SkCanvas * canvas,const SkPaint & paint)27 void 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)
test_bowtie(SkCanvas * canvas,const SkPaint & paint)40 void 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)
test_fake_bowtie(SkCanvas * canvas,const SkPaint & paint)53 void 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)
test_fish(SkCanvas * canvas,const SkPaint & paint)68 void 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
test_collinear_edges(SkCanvas * canvas,const SkPaint & paint)83 void 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.
test_hole(SkCanvas * canvas,const SkPaint & paint)96 void 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)
test_star(SkCanvas * canvas,const SkPaint & paint)113 void 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)
test_stairstep(SkCanvas * canvas,const SkPaint & paint)128 void 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 
test_stairstep2(SkCanvas * canvas,const SkPaint & paint)142 void 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
test_overlapping(SkCanvas * canvas,const SkPaint & paint)156 void 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)
test_monotone_1(SkCanvas * canvas,const SkPaint & paint)169 void 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)
test_monotone_2(SkCanvas * canvas,const SkPaint & paint)183 void 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)
test_monotone_3(SkCanvas * canvas,const SkPaint & paint)196 void 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)
test_monotone_4(SkCanvas * canvas,const SkPaint & paint)209 void 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)
test_monotone_5(SkCanvas * canvas,const SkPaint & paint)224 void 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
test_degenerate(SkCanvas * canvas,const SkPaint & paint)236 void 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.
test_coincident_edge(SkCanvas * canvas,const SkPaint & paint)250 void 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).
test_bowtie_coincident_triangle(SkCanvas * canvas,const SkPaint & paint)268 void 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).
test_coincident_edges_1(SkCanvas * canvas,const SkPaint & paint)284 void 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).
test_coincident_edges_2(SkCanvas * canvas,const SkPaint & paint)298 void 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).
test_coincident_edges_3(SkCanvas * canvas,const SkPaint & paint)312 void 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).
test_coincident_edges_4(SkCanvas * canvas,const SkPaint & paint)326 void 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 
342 class ConcavePathsGM : public skiagm::GM {
343 public:
ConcavePathsGM()344     ConcavePathsGM() {}
345 
346 protected:
onShortName()347     SkString onShortName() override {
348         return SkString("concavepaths");
349     }
350 
onISize()351     SkISize onISize() override {
352         return SkISize::Make(WIDTH, HEIGHT);
353     }
354 
onDraw(SkCanvas * canvas)355     void onDraw(SkCanvas* canvas) override {
356         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 
386 private:
387     typedef skiagm::GM INHERITED;
388 };
389 
F0(void *)390 static skiagm::GM* F0(void*) { return new ConcavePathsGM; }
391 static skiagm::GMRegistry R0(F0);
392