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