1 /*
2  * Copyright 2017 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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkPaint.h"
11 #include "include/core/SkPath.h"
12 #include "include/core/SkScalar.h"
13 
14 namespace {
15 // Test thin stroked rect (stroked "by hand", not by stroking).
draw_thin_stroked_rect(SkCanvas * canvas,const SkPaint & paint,SkScalar width)16 void draw_thin_stroked_rect(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
17     SkPath path;
18     path.moveTo(10 + width, 10 + width);
19     path.lineTo(40,         10 + width);
20     path.lineTo(40,         20);
21     path.lineTo(10 + width, 20);
22     path.moveTo(10,         10);
23     path.lineTo(10,         20 + width);
24     path.lineTo(40 + width, 20 + width);
25     path.lineTo(40 + width, 10);
26     canvas->drawPath(path, paint);
27 }
28 
draw_thin_right_angle(SkCanvas * canvas,const SkPaint & paint,SkScalar width)29 void draw_thin_right_angle(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
30     SkPath path;
31     path.moveTo(10 + width, 10 + width);
32     path.lineTo(40,         10 + width);
33     path.lineTo(40,         20);
34     path.lineTo(40 + width, 20 + width);
35     path.lineTo(40 + width, 10);
36     path.lineTo(10,         10);
37     canvas->drawPath(path, paint);
38 }
39 
40 // Test thin horizontal line (<1 pixel) which should give lower alpha.
draw_golf_club(SkCanvas * canvas,const SkPaint & paint,SkScalar width)41 void draw_golf_club(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
42     SkPath path;
43     path.moveTo(20, 10);
44     path.lineTo(80, 10);
45     path.lineTo(80, 10 + width);
46     path.lineTo(30, 10 + width);
47     path.lineTo(30, 20);
48     path.lineTo(20, 20);
49     canvas->drawPath(path, paint);
50 }
51 
52 // Test thin lines between two filled regions. The outer edges overlap, but
53 // there are no inverted edges to fix.
draw_barbell(SkCanvas * canvas,const SkPaint & paint,SkScalar width)54 void draw_barbell(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
55     SkScalar offset = width * 0.5f;
56     SkPath path;
57     path.moveTo(30,  5);
58     path.lineTo(40 - offset, 15 - offset);
59     path.lineTo(60 + offset, 15 - offset);
60     path.lineTo(70,  5);
61     path.lineTo(70, 25);
62     path.lineTo(60 + offset, 15 + offset);
63     path.lineTo(40 - offset, 15 + offset);
64     path.lineTo(30, 25);
65     canvas->drawPath(path, paint);
66 }
67 
68 // Test a thin rectangle and triangle. The top and bottom inner edges of the
69 // rectangle and all inner edges of the triangle invert on stroking.
draw_thin_rect_and_triangle(SkCanvas * canvas,const SkPaint & paint,SkScalar width)70 void draw_thin_rect_and_triangle(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
71     SkPath path;
72     path.moveTo(30,  5);
73     path.lineTo(30 + width,  5);
74     path.lineTo(30 + width,  25);
75     path.lineTo(30,  25);
76     path.moveTo(40,  5);
77     path.lineTo(40 + width,  5);
78     path.lineTo(40,  25);
79     canvas->drawPath(path, paint);
80 }
81 
82 // Two triangles joined by a very thin bridge. The tiny triangle formed
83 // by the inner edges at the bridge is inverted.
84 // (These are actually now more phat pants than hipster pants.)
draw_hipster_pants(SkCanvas * canvas,const SkPaint & paint,SkScalar width)85 void draw_hipster_pants(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
86     SkPath path;
87     path.moveTo(10, 10);
88     path.lineTo(10, 20);
89     path.lineTo(50, 10 + width);
90     path.lineTo(90, 20);
91     path.lineTo(90, 10);
92     canvas->drawPath(path, paint);
93 }
94 
95 // A thin z-shape whose interior inverts on stroking. The top and bottom inner edges invert, and
96 // the connector edges at the "elbows" intersect the inner edges.
draw_skinny_snake(SkCanvas * canvas,const SkPaint & paint,SkScalar width)97 void draw_skinny_snake(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
98     SkPath path;
99     path.moveTo(20 + width, 10);
100     path.lineTo(20 + width, 20);
101     path.lineTo(10 + width, 30);
102     path.lineTo(10 + width, 40);
103     path.lineTo(10 - width, 40);
104     path.lineTo(10 - width, 30);
105     path.lineTo(20 - width, 20);
106     path.lineTo(20 - width, 10);
107     canvas->drawPath(path, paint);
108 }
109 
110 // Test pointy features whose outer edges extend far to the right on stroking.
draw_pointy_golf_club(SkCanvas * canvas,const SkPaint & paint,SkScalar width)111 void draw_pointy_golf_club(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
112     SkPath path;
113     path.moveTo(20, 10);
114     path.lineTo(80, 10 + width * 0.5);
115     path.lineTo(30, 10 + width);
116     path.lineTo(30, 20);
117     path.lineTo(20, 20);
118     canvas->drawPath(path, paint);
119 }
120 
draw_small_i(SkCanvas * canvas,const SkPaint & paint,SkScalar width)121 void draw_small_i(SkCanvas* canvas, const SkPaint& paint, SkScalar width) {
122     SkPath path;
123     path.moveTo(1.25 - width, 18.75 + width);
124     path.lineTo(1.25 - width, 12.25 - width);
125     path.lineTo(2.50 + width, 12.25 - width);
126     path.lineTo(2.50 + width, 18.75 + width);
127     path.moveTo(1.25 - width, 11.75 + width);
128     path.lineTo(1.25 - width, 10.25 - width);
129     path.lineTo(2.50 + width, 10.25 - width);
130     path.lineTo(2.50 + width, 11.75 + width);
131     canvas->drawPath(path, paint);
132 }
133 
134 
135 
136 }  // namespace
137 
138 DEF_SIMPLE_GM(thinconcavepaths, canvas, 550, 400) {
139     SkPaint paint;
140 
141     paint.setAntiAlias(true);
142     paint.setStyle(SkPaint::kFill_Style);
143 
144     canvas->save();
145     for (SkScalar width = 0.5f; width < 2.05f; width += 0.25f) {
146         draw_thin_stroked_rect(canvas, paint, width);
147         canvas->translate(0, 25);
148     }
149     canvas->restore();
150     canvas->translate(50, 0);
151     canvas->save();
152     for (SkScalar width = 0.5f; width < 2.05f; width += 0.25f) {
153         draw_thin_right_angle(canvas, paint, width);
154         canvas->translate(0, 25);
155     }
156     canvas->restore();
157     canvas->translate(40, 0);
158     canvas->save();
159     for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) {
160         draw_golf_club(canvas, paint, width);
161         canvas->translate(0, 30);
162     }
163     canvas->restore();
164     canvas->translate(70, 0);
165     canvas->save();
166     for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) {
167         draw_thin_rect_and_triangle(canvas, paint, width);
168         canvas->translate(0, 30);
169     }
170     canvas->restore();
171     canvas->translate(30, 0);
172     canvas->save();
173 
174     for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) {
175         draw_barbell(canvas, paint, width);
176         canvas->translate(0, 30);
177     }
178     canvas->restore();
179     canvas->translate(80, 0);
180     canvas->save();
181     for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) {
182         draw_hipster_pants(canvas, paint, width);
183         canvas->translate(0, 30);
184     }
185     canvas->restore();
186     canvas->translate(100, 0);
187     canvas->save();
188     for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) {
189         draw_skinny_snake(canvas, paint, width);
190         canvas->translate(0, 30);
191     }
192     canvas->restore();
193     canvas->translate(30, 0);
194     canvas->save();
195     for (SkScalar width = 0.2f; width < 2.1f; width += 0.2f) {
196         draw_pointy_golf_club(canvas, paint, width);
197         canvas->translate(0, 30);
198     }
199     canvas->restore();
200     canvas->translate(100, 0);
201     canvas->save();
202     for (SkScalar width = 0.0f; width < 0.5f; width += 0.05f) {
203         draw_small_i(canvas, paint, width);
204         canvas->translate(0, 30);
205     }
206     canvas->restore();
207     canvas->translate(100, 0);
208 }
209