1 /*
2 * Copyright 2011 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 "SkPath.h"
10
11 typedef SkScalar (*MakePathProc)(SkPath*);
12
make_frame(SkPath * path)13 static SkScalar make_frame(SkPath* path) {
14 SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
15 SkIntToScalar(630), SkIntToScalar(470) };
16 path->addRoundRect(r, SkIntToScalar(15), SkIntToScalar(15));
17
18 SkPaint paint;
19 paint.setStyle(SkPaint::kStroke_Style);
20 paint.setStrokeWidth(SkIntToScalar(5));
21 paint.getFillPath(*path, path);
22 return SkIntToScalar(15);
23 }
24
make_triangle(SkPath * path)25 static SkScalar make_triangle(SkPath* path) {
26 constexpr int gCoord[] = {
27 10, 20, 15, 5, 30, 30
28 };
29 path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
30 path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
31 path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
32 path->close();
33 path->offset(SkIntToScalar(10), SkIntToScalar(0));
34 return SkIntToScalar(30);
35 }
36
make_rect(SkPath * path)37 static SkScalar make_rect(SkPath* path) {
38 SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
39 SkIntToScalar(30), SkIntToScalar(30) };
40 path->addRect(r);
41 path->offset(SkIntToScalar(10), SkIntToScalar(0));
42 return SkIntToScalar(30);
43 }
44
make_oval(SkPath * path)45 static SkScalar make_oval(SkPath* path) {
46 SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
47 SkIntToScalar(30), SkIntToScalar(30) };
48 path->addOval(r);
49 path->offset(SkIntToScalar(10), SkIntToScalar(0));
50 return SkIntToScalar(30);
51 }
52
make_sawtooth(SkPath * path,int teeth)53 static SkScalar make_sawtooth(SkPath* path, int teeth) {
54 SkScalar x = SkIntToScalar(20);
55 SkScalar y = SkIntToScalar(20);
56 const SkScalar x0 = x;
57 const SkScalar dx = SkIntToScalar(5);
58 const SkScalar dy = SkIntToScalar(10);
59
60 path->moveTo(x, y);
61 for (int i = 0; i < teeth; i++) {
62 x += dx;
63 path->lineTo(x, y - dy);
64 x += dx;
65 path->lineTo(x, y + dy);
66 }
67 path->lineTo(x, y + (2 * dy));
68 path->lineTo(x0, y + (2 * dy));
69 path->close();
70 return SkIntToScalar(30);
71 }
72
make_sawtooth_3(SkPath * path)73 static SkScalar make_sawtooth_3(SkPath* path) { return make_sawtooth(path, 3); }
make_sawtooth_32(SkPath * path)74 static SkScalar make_sawtooth_32(SkPath* path) { return make_sawtooth(path, 32); }
75
make_house(SkPath * path)76 static SkScalar make_house(SkPath* path) {
77 path->moveTo(21, 23);
78 path->lineTo(21, 11.534f);
79 path->lineTo(22.327f, 12.741f);
80 path->lineTo(23.673f, 11.261f);
81 path->lineTo(12, 0.648f);
82 path->lineTo(8, 4.285f);
83 path->lineTo(8, 2);
84 path->lineTo(4, 2);
85 path->lineTo(4, 7.921f);
86 path->lineTo(0.327f, 11.26f);
87 path->lineTo(1.673f, 12.74f);
88 path->lineTo(3, 11.534f);
89 path->lineTo(3, 23);
90 path->lineTo(11, 23);
91 path->lineTo(11, 18);
92 path->lineTo(13, 18);
93 path->lineTo(13, 23);
94 path->lineTo(21, 23);
95 path->close();
96 path->lineTo(9, 16);
97 path->lineTo(9, 21);
98 path->lineTo(5, 21);
99 path->lineTo(5, 9.715f);
100 path->lineTo(12, 3.351f);
101 path->lineTo(19, 9.715f);
102 path->lineTo(19, 21);
103 path->lineTo(15, 21);
104 path->lineTo(15, 16);
105 path->lineTo(9, 16);
106 path->close();
107 path->offset(20, 0);
108 return SkIntToScalar(30);
109 }
110
make_star(SkPath * path,int n)111 static SkScalar make_star(SkPath* path, int n) {
112 const SkScalar c = SkIntToScalar(45);
113 const SkScalar r = SkIntToScalar(20);
114
115 SkScalar rad = -SK_ScalarPI / 2;
116 const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
117
118 path->moveTo(c, c - r);
119 for (int i = 1; i < n; i++) {
120 rad += drad;
121 SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
122 path->lineTo(c + cosV * r, c + sinV * r);
123 }
124 path->close();
125 return r * 2 * 6 / 5;
126 }
127
make_star_5(SkPath * path)128 static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
make_star_13(SkPath * path)129 static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
130
131 // We don't expect any output from this path.
make_line(SkPath * path)132 static SkScalar make_line(SkPath* path) {
133 path->moveTo(SkIntToScalar(30), SkIntToScalar(30));
134 path->lineTo(SkIntToScalar(120), SkIntToScalar(40));
135 path->close();
136 path->moveTo(SkIntToScalar(150), SkIntToScalar(30));
137 path->lineTo(SkIntToScalar(150), SkIntToScalar(30));
138 path->lineTo(SkIntToScalar(300), SkIntToScalar(40));
139 path->close();
140 return SkIntToScalar(40);
141 }
142
make_info(SkPath * path)143 static void make_info(SkPath* path) {
144 path->moveTo(24, 4);
145 path->cubicTo(12.94999980926514f,
146 4,
147 4,
148 12.94999980926514f,
149 4,
150 24);
151 path->cubicTo(4,
152 35.04999923706055f,
153 12.94999980926514f,
154 44,
155 24,
156 44);
157 path->cubicTo(35.04999923706055f,
158 44,
159 44,
160 35.04999923706055f,
161 44,
162 24);
163 path->cubicTo(44,
164 12.95000076293945f,
165 35.04999923706055f,
166 4,
167 24,
168 4);
169 path->close();
170 path->moveTo(26, 34);
171 path->lineTo(22, 34);
172 path->lineTo(22, 22);
173 path->lineTo(26, 22);
174 path->lineTo(26, 34);
175 path->close();
176 path->moveTo(26, 18);
177 path->lineTo(22, 18);
178 path->lineTo(22, 14);
179 path->lineTo(26, 14);
180 path->lineTo(26, 18);
181 path->close();
182 }
183
make_accessibility(SkPath * path)184 static void make_accessibility(SkPath* path) {
185 path->moveTo(12, 2);
186 path->cubicTo(13.10000038146973f,
187 2,
188 14,
189 2.900000095367432f,
190 14,
191 4);
192 path->cubicTo(14,
193 5.099999904632568f,
194 13.10000038146973f,
195 6,
196 12,
197 6);
198 path->cubicTo(10.89999961853027f,
199 6,
200 10,
201 5.099999904632568f,
202 10,
203 4);
204 path->cubicTo(10,
205 2.900000095367432f,
206 10.89999961853027f,
207 2,
208 12,
209 2);
210 path->close();
211 path->moveTo(21, 9);
212 path->lineTo(15, 9);
213 path->lineTo(15, 22);
214 path->lineTo(13, 22);
215 path->lineTo(13, 16);
216 path->lineTo(11, 16);
217 path->lineTo(11, 22);
218 path->lineTo(9, 22);
219 path->lineTo(9, 9);
220 path->lineTo(3, 9);
221 path->lineTo(3, 7);
222 path->lineTo(21, 7);
223 path->lineTo(21, 9);
224 path->close();
225 }
226
227 // test case for http://crbug.com/695196
make_visualizer(SkPath * path)228 static void make_visualizer(SkPath* path) {
229 path->moveTo(1.9520f, 2.0000f);
230 path->conicTo(1.5573f, 1.9992f, 1.2782f, 2.2782f, 0.9235f);
231 path->conicTo(0.9992f, 2.5573f, 1.0000f, 2.9520f, 0.9235f);
232 path->lineTo(1.0000f, 5.4300f);
233 path->lineTo(17.0000f, 5.4300f);
234 path->lineTo(17.0000f, 2.9520f);
235 path->conicTo(17.0008f, 2.5573f, 16.7218f, 2.2782f, 0.9235f);
236 path->conicTo(16.4427f, 1.9992f, 16.0480f, 2.0000f, 0.9235f);
237 path->lineTo(1.9520f, 2.0000f);
238 path->close();
239 path->moveTo(2.7140f, 3.1430f);
240 path->conicTo(3.0547f, 3.1287f, 3.2292f, 3.4216f, 0.8590f);
241 path->conicTo(3.4038f, 3.7145f, 3.2292f, 4.0074f, 0.8590f);
242 path->conicTo(3.0547f, 4.3003f, 2.7140f, 4.2860f, 0.8590f);
243 path->conicTo(2.1659f, 4.2631f, 2.1659f, 3.7145f, 0.7217f);
244 path->conicTo(2.1659f, 3.1659f, 2.7140f, 3.1430f, 0.7217f);
245 path->lineTo(2.7140f, 3.1430f);
246 path->close();
247 path->moveTo(5.0000f, 3.1430f);
248 path->conicTo(5.3407f, 3.1287f, 5.5152f, 3.4216f, 0.8590f);
249 path->conicTo(5.6898f, 3.7145f, 5.5152f, 4.0074f, 0.8590f);
250 path->conicTo(5.3407f, 4.3003f, 5.0000f, 4.2860f, 0.8590f);
251 path->conicTo(4.4519f, 4.2631f, 4.4519f, 3.7145f, 0.7217f);
252 path->conicTo(4.4519f, 3.1659f, 5.0000f, 3.1430f, 0.7217f);
253 path->lineTo(5.0000f, 3.1430f);
254 path->close();
255 path->moveTo(7.2860f, 3.1430f);
256 path->conicTo(7.6267f, 3.1287f, 7.8012f, 3.4216f, 0.8590f);
257 path->conicTo(7.9758f, 3.7145f, 7.8012f, 4.0074f, 0.8590f);
258 path->conicTo(7.6267f, 4.3003f, 7.2860f, 4.2860f, 0.8590f);
259 path->conicTo(6.7379f, 4.2631f, 6.7379f, 3.7145f, 0.7217f);
260 path->conicTo(6.7379f, 3.1659f, 7.2860f, 3.1430f, 0.7217f);
261 path->close();
262 path->moveTo(1.0000f, 6.1900f);
263 path->lineTo(1.0000f, 14.3810f);
264 path->conicTo(0.9992f, 14.7757f, 1.2782f, 15.0548f, 0.9235f);
265 path->conicTo(1.5573f, 15.3338f, 1.9520f, 15.3330f, 0.9235f);
266 path->lineTo(16.0480f, 15.3330f);
267 path->conicTo(16.4427f, 15.3338f, 16.7218f, 15.0548f, 0.9235f);
268 path->conicTo(17.0008f, 14.7757f, 17.0000f, 14.3810f, 0.9235f);
269 path->lineTo(17.0000f, 6.1910f);
270 path->lineTo(1.0000f, 6.1910f);
271 path->lineTo(1.0000f, 6.1900f);
272 path->close();
273 }
274
275 constexpr MakePathProc gProcs[] = {
276 make_frame,
277 make_triangle,
278 make_rect,
279 make_oval,
280 make_sawtooth_32,
281 make_star_5,
282 make_star_13,
283 make_line,
284 make_house,
285 make_sawtooth_3,
286 };
287
288 #define N SK_ARRAY_COUNT(gProcs)
289
290 class PathFillGM : public skiagm::GM {
291 SkPath fPath[N];
292 SkScalar fDY[N];
293 SkPath fInfoPath;
294 SkPath fAccessibilityPath;
295 SkPath fVisualizerPath;
296 protected:
onOnceBeforeDraw()297 void onOnceBeforeDraw() override {
298 for (size_t i = 0; i < N; i++) {
299 fDY[i] = gProcs[i](&fPath[i]);
300 }
301
302 make_info(&fInfoPath);
303 make_accessibility(&fAccessibilityPath);
304 make_visualizer(&fVisualizerPath);
305 }
306
307
onShortName()308 SkString onShortName() override {
309 return SkString("pathfill");
310 }
311
onISize()312 SkISize onISize() override {
313 return SkISize::Make(640, 480);
314 }
315
onDraw(SkCanvas * canvas)316 void onDraw(SkCanvas* canvas) override {
317 SkPaint paint;
318 paint.setAntiAlias(true);
319
320 for (size_t i = 0; i < N; i++) {
321 canvas->drawPath(fPath[i], paint);
322 canvas->translate(SkIntToScalar(0), fDY[i]);
323 }
324
325 canvas->save();
326 canvas->scale(0.300000011920929f, 0.300000011920929f);
327 canvas->translate(50, 50);
328 canvas->drawPath(fInfoPath, paint);
329 canvas->restore();
330
331 canvas->scale(2, 2);
332 canvas->translate(5, 15);
333 canvas->drawPath(fAccessibilityPath, paint);
334
335 canvas->scale(0.5f, 0.5f);
336 canvas->translate(5, 50);
337 canvas->drawPath(fVisualizerPath, paint);
338 }
339
340 private:
341 typedef skiagm::GM INHERITED;
342 };
343
344 // test inverse-fill w/ a clip that completely excludes the geometry
345 class PathInverseFillGM : public skiagm::GM {
346 SkPath fPath[N];
347 SkScalar fDY[N];
348 protected:
onOnceBeforeDraw()349 void onOnceBeforeDraw() override {
350 for (size_t i = 0; i < N; i++) {
351 fDY[i] = gProcs[i](&fPath[i]);
352 }
353 }
354
onShortName()355 SkString onShortName() override {
356 return SkString("pathinvfill");
357 }
358
onISize()359 SkISize onISize() override {
360 return SkISize::Make(450, 220);
361 }
362
show(SkCanvas * canvas,const SkPath & path,const SkPaint & paint,const SkRect * clip,SkScalar top,const SkScalar bottom)363 static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint,
364 const SkRect* clip, SkScalar top, const SkScalar bottom) {
365 canvas->save();
366 if (clip) {
367 SkRect r = *clip;
368 r.fTop = top;
369 r.fBottom = bottom;
370 canvas->clipRect(r);
371 }
372 canvas->drawPath(path, paint);
373 canvas->restore();
374 }
375
onDraw(SkCanvas * canvas)376 void onDraw(SkCanvas* canvas) override {
377 SkPath path;
378
379 path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40));
380 path.toggleInverseFillType();
381
382 SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) };
383
384 canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
385
386 for (int doclip = 0; doclip <= 1; ++doclip) {
387 for (int aa = 0; aa <= 1; ++aa) {
388 SkPaint paint;
389 paint.setAntiAlias(SkToBool(aa));
390
391 canvas->save();
392 canvas->clipRect(clipR);
393
394 const SkRect* clipPtr = doclip ? &clipR : nullptr;
395
396 show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY());
397 show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom);
398
399 canvas->restore();
400 canvas->translate(SkIntToScalar(110), 0);
401 }
402 }
403 }
404
405 private:
406 typedef skiagm::GM INHERITED;
407 };
408
409 DEF_SIMPLE_GM(rotatedcubicpath, canvas, 200, 200) {
410 SkPaint p;
411 p.setAntiAlias(true);
412 p.setStyle(SkPaint::kFill_Style);
413
414 canvas->translate(50, 50);
415 SkPath path;
416 path.moveTo(48,-23);
417 path.cubicTo(48,-29.5, 6,-30, 6,-30);
418 path.cubicTo(6,-30, 2,0, 2,0);
419 path.cubicTo(2,0, 44,-21.5, 48,-23);
420 path.close();
421
422 p.setColor(SK_ColorBLUE);
423 canvas->drawPath(path, p);
424
425 // Rotated path, which is not antialiased on GPU
426 p.setColor(SK_ColorRED);
427 canvas->rotate(90);
428 canvas->drawPath(path, p);
429 }
430
431 ///////////////////////////////////////////////////////////////////////////////
432
433 DEF_GM( return new PathFillGM; )
434 DEF_GM( return new PathInverseFillGM; )
435