• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkRect.h"
14 #include "include/core/SkScalar.h"
15 #include "include/core/SkSize.h"
16 #include "include/core/SkString.h"
17 #include "include/core/SkTypes.h"
18 
19 typedef SkScalar (*MakePathProc)(SkPath*);
20 
make_frame(SkPath * path)21 static SkScalar make_frame(SkPath* path) {
22     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
23                  SkIntToScalar(630), SkIntToScalar(470) };
24     path->addRoundRect(r, SkIntToScalar(15), SkIntToScalar(15));
25 
26     SkPaint paint;
27     paint.setStyle(SkPaint::kStroke_Style);
28     paint.setStrokeWidth(SkIntToScalar(5));
29     paint.getFillPath(*path, path);
30     return SkIntToScalar(15);
31 }
32 
make_triangle(SkPath * path)33 static SkScalar make_triangle(SkPath* path) {
34     constexpr int gCoord[] = {
35         10, 20, 15, 5, 30, 30
36     };
37     path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
38     path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
39     path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
40     path->close();
41     path->offset(SkIntToScalar(10), SkIntToScalar(0));
42     return SkIntToScalar(30);
43 }
44 
make_rect(SkPath * path)45 static SkScalar make_rect(SkPath* path) {
46     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
47                  SkIntToScalar(30), SkIntToScalar(30) };
48     path->addRect(r);
49     path->offset(SkIntToScalar(10), SkIntToScalar(0));
50     return SkIntToScalar(30);
51 }
52 
make_oval(SkPath * path)53 static SkScalar make_oval(SkPath* path) {
54     SkRect r = { SkIntToScalar(10), SkIntToScalar(10),
55                  SkIntToScalar(30), SkIntToScalar(30) };
56     path->addOval(r);
57     path->offset(SkIntToScalar(10), SkIntToScalar(0));
58     return SkIntToScalar(30);
59 }
60 
make_sawtooth(SkPath * path,int teeth)61 static SkScalar make_sawtooth(SkPath* path, int teeth) {
62     SkScalar x = SkIntToScalar(20);
63     SkScalar y = SkIntToScalar(20);
64     const SkScalar x0 = x;
65     const SkScalar dx = SkIntToScalar(5);
66     const SkScalar dy = SkIntToScalar(10);
67 
68     path->moveTo(x, y);
69     for (int i = 0; i < teeth; i++) {
70         x += dx;
71         path->lineTo(x, y - dy);
72         x += dx;
73         path->lineTo(x, y + dy);
74     }
75     path->lineTo(x, y + (2 * dy));
76     path->lineTo(x0, y + (2 * dy));
77     path->close();
78     return SkIntToScalar(30);
79 }
80 
make_sawtooth_3(SkPath * path)81 static SkScalar make_sawtooth_3(SkPath* path) { return make_sawtooth(path, 3); }
make_sawtooth_32(SkPath * path)82 static SkScalar make_sawtooth_32(SkPath* path) { return make_sawtooth(path, 32); }
83 
make_house(SkPath * path)84 static SkScalar make_house(SkPath* path) {
85     path->moveTo(21, 23);
86     path->lineTo(21, 11.534f);
87     path->lineTo(22.327f, 12.741f);
88     path->lineTo(23.673f, 11.261f);
89     path->lineTo(12, 0.648f);
90     path->lineTo(8, 4.285f);
91     path->lineTo(8, 2);
92     path->lineTo(4, 2);
93     path->lineTo(4, 7.921f);
94     path->lineTo(0.327f, 11.26f);
95     path->lineTo(1.673f, 12.74f);
96     path->lineTo(3, 11.534f);
97     path->lineTo(3, 23);
98     path->lineTo(11, 23);
99     path->lineTo(11, 18);
100     path->lineTo(13, 18);
101     path->lineTo(13, 23);
102     path->lineTo(21, 23);
103     path->close();
104     path->lineTo(9, 16);
105     path->lineTo(9, 21);
106     path->lineTo(5, 21);
107     path->lineTo(5, 9.715f);
108     path->lineTo(12, 3.351f);
109     path->lineTo(19, 9.715f);
110     path->lineTo(19, 21);
111     path->lineTo(15, 21);
112     path->lineTo(15, 16);
113     path->lineTo(9, 16);
114     path->close();
115     path->offset(20, 0);
116     return SkIntToScalar(30);
117 }
118 
make_star(SkPath * path,int n)119 static SkScalar make_star(SkPath* path, int n) {
120     const SkScalar c = SkIntToScalar(45);
121     const SkScalar r = SkIntToScalar(20);
122 
123     SkScalar rad = -SK_ScalarPI / 2;
124     const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
125 
126     path->moveTo(c, c - r);
127     for (int i = 1; i < n; i++) {
128         rad += drad;
129         path->lineTo(c + SkScalarCos(rad) * r, c + SkScalarSin(rad) * r);
130     }
131     path->close();
132     return r * 2 * 6 / 5;
133 }
134 
make_star_5(SkPath * path)135 static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
make_star_13(SkPath * path)136 static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
137 
138 // We don't expect any output from this path.
make_line(SkPath * path)139 static SkScalar make_line(SkPath* path) {
140     path->moveTo(SkIntToScalar(30), SkIntToScalar(30));
141     path->lineTo(SkIntToScalar(120), SkIntToScalar(40));
142     path->close();
143     path->moveTo(SkIntToScalar(150), SkIntToScalar(30));
144     path->lineTo(SkIntToScalar(150), SkIntToScalar(30));
145     path->lineTo(SkIntToScalar(300), SkIntToScalar(40));
146     path->close();
147     return SkIntToScalar(40);
148 }
149 
make_info(SkPath * path)150 static void make_info(SkPath* path) {
151     path->moveTo(24, 4);
152     path->cubicTo(12.94999980926514f,
153                   4,
154                   4,
155                   12.94999980926514f,
156                   4,
157                   24);
158     path->cubicTo(4,
159                   35.04999923706055f,
160                   12.94999980926514f,
161                   44,
162                   24,
163                   44);
164     path->cubicTo(35.04999923706055f,
165                   44,
166                   44,
167                   35.04999923706055f,
168                   44,
169                   24);
170     path->cubicTo(44,
171                   12.95000076293945f,
172                   35.04999923706055f,
173                   4,
174                   24,
175                   4);
176     path->close();
177     path->moveTo(26, 34);
178     path->lineTo(22, 34);
179     path->lineTo(22, 22);
180     path->lineTo(26, 22);
181     path->lineTo(26, 34);
182     path->close();
183     path->moveTo(26, 18);
184     path->lineTo(22, 18);
185     path->lineTo(22, 14);
186     path->lineTo(26, 14);
187     path->lineTo(26, 18);
188     path->close();
189 }
190 
make_accessibility(SkPath * path)191 static void make_accessibility(SkPath* path) {
192     path->moveTo(12, 2);
193     path->cubicTo(13.10000038146973f,
194                   2,
195                   14,
196                   2.900000095367432f,
197                   14,
198                   4);
199     path->cubicTo(14,
200                   5.099999904632568f,
201                   13.10000038146973f,
202                   6,
203                   12,
204                   6);
205     path->cubicTo(10.89999961853027f,
206                   6,
207                   10,
208                   5.099999904632568f,
209                   10,
210                   4);
211     path->cubicTo(10,
212                   2.900000095367432f,
213                   10.89999961853027f,
214                   2,
215                   12,
216                   2);
217     path->close();
218     path->moveTo(21, 9);
219     path->lineTo(15, 9);
220     path->lineTo(15, 22);
221     path->lineTo(13, 22);
222     path->lineTo(13, 16);
223     path->lineTo(11, 16);
224     path->lineTo(11, 22);
225     path->lineTo(9, 22);
226     path->lineTo(9, 9);
227     path->lineTo(3, 9);
228     path->lineTo(3, 7);
229     path->lineTo(21, 7);
230     path->lineTo(21, 9);
231     path->close();
232 }
233 
234 // test case for http://crbug.com/695196
make_visualizer(SkPath * path)235 static void make_visualizer(SkPath* path) {
236     path->moveTo(1.9520f, 2.0000f);
237     path->conicTo(1.5573f, 1.9992f, 1.2782f, 2.2782f, 0.9235f);
238     path->conicTo(0.9992f, 2.5573f, 1.0000f, 2.9520f, 0.9235f);
239     path->lineTo(1.0000f, 5.4300f);
240     path->lineTo(17.0000f, 5.4300f);
241     path->lineTo(17.0000f, 2.9520f);
242     path->conicTo(17.0008f, 2.5573f, 16.7218f, 2.2782f, 0.9235f);
243     path->conicTo(16.4427f, 1.9992f, 16.0480f, 2.0000f, 0.9235f);
244     path->lineTo(1.9520f, 2.0000f);
245     path->close();
246     path->moveTo(2.7140f, 3.1430f);
247     path->conicTo(3.0547f, 3.1287f, 3.2292f, 3.4216f, 0.8590f);
248     path->conicTo(3.4038f, 3.7145f, 3.2292f, 4.0074f, 0.8590f);
249     path->conicTo(3.0547f, 4.3003f, 2.7140f, 4.2860f, 0.8590f);
250     path->conicTo(2.1659f, 4.2631f, 2.1659f, 3.7145f, 0.7217f);
251     path->conicTo(2.1659f, 3.1659f, 2.7140f, 3.1430f, 0.7217f);
252     path->lineTo(2.7140f, 3.1430f);
253     path->close();
254     path->moveTo(5.0000f, 3.1430f);
255     path->conicTo(5.3407f, 3.1287f, 5.5152f, 3.4216f, 0.8590f);
256     path->conicTo(5.6898f, 3.7145f, 5.5152f, 4.0074f, 0.8590f);
257     path->conicTo(5.3407f, 4.3003f, 5.0000f, 4.2860f, 0.8590f);
258     path->conicTo(4.4519f, 4.2631f, 4.4519f, 3.7145f, 0.7217f);
259     path->conicTo(4.4519f, 3.1659f, 5.0000f, 3.1430f, 0.7217f);
260     path->lineTo(5.0000f, 3.1430f);
261     path->close();
262     path->moveTo(7.2860f, 3.1430f);
263     path->conicTo(7.6267f, 3.1287f, 7.8012f, 3.4216f, 0.8590f);
264     path->conicTo(7.9758f, 3.7145f, 7.8012f, 4.0074f, 0.8590f);
265     path->conicTo(7.6267f, 4.3003f, 7.2860f, 4.2860f, 0.8590f);
266     path->conicTo(6.7379f, 4.2631f, 6.7379f, 3.7145f, 0.7217f);
267     path->conicTo(6.7379f, 3.1659f, 7.2860f, 3.1430f, 0.7217f);
268     path->close();
269     path->moveTo(1.0000f, 6.1900f);
270     path->lineTo(1.0000f, 14.3810f);
271     path->conicTo(0.9992f, 14.7757f, 1.2782f, 15.0548f, 0.9235f);
272     path->conicTo(1.5573f, 15.3338f, 1.9520f, 15.3330f, 0.9235f);
273     path->lineTo(16.0480f, 15.3330f);
274     path->conicTo(16.4427f, 15.3338f, 16.7218f, 15.0548f, 0.9235f);
275     path->conicTo(17.0008f, 14.7757f, 17.0000f, 14.3810f, 0.9235f);
276     path->lineTo(17.0000f, 6.1910f);
277     path->lineTo(1.0000f, 6.1910f);
278     path->lineTo(1.0000f, 6.1900f);
279     path->close();
280 }
281 
282 constexpr MakePathProc gProcs[] = {
283     make_frame,
284     make_triangle,
285     make_rect,
286     make_oval,
287     make_sawtooth_32,
288     make_star_5,
289     make_star_13,
290     make_line,
291     make_house,
292     make_sawtooth_3,
293 };
294 
295 #define N   SK_ARRAY_COUNT(gProcs)
296 
297 class PathFillGM : public skiagm::GM {
298     SkPath  fPath[N];
299     SkScalar fDY[N];
300     SkPath  fInfoPath;
301     SkPath  fAccessibilityPath;
302     SkPath  fVisualizerPath;
303 protected:
onOnceBeforeDraw()304     void onOnceBeforeDraw() override {
305         for (size_t i = 0; i < N; i++) {
306             fDY[i] = gProcs[i](&fPath[i]);
307         }
308 
309         make_info(&fInfoPath);
310         make_accessibility(&fAccessibilityPath);
311         make_visualizer(&fVisualizerPath);
312     }
313 
314 
onShortName()315     SkString onShortName() override {
316         return SkString("pathfill");
317     }
318 
onISize()319     SkISize onISize() override {
320         return SkISize::Make(640, 480);
321     }
322 
onDraw(SkCanvas * canvas)323     void onDraw(SkCanvas* canvas) override {
324         SkPaint paint;
325         paint.setAntiAlias(true);
326 
327         for (size_t i = 0; i < N; i++) {
328             canvas->drawPath(fPath[i], paint);
329             canvas->translate(SkIntToScalar(0), fDY[i]);
330         }
331 
332         canvas->save();
333         canvas->scale(0.300000011920929f, 0.300000011920929f);
334         canvas->translate(50, 50);
335         canvas->drawPath(fInfoPath, paint);
336         canvas->restore();
337 
338         canvas->scale(2, 2);
339         canvas->translate(5, 15);
340         canvas->drawPath(fAccessibilityPath, paint);
341 
342         canvas->scale(0.5f, 0.5f);
343         canvas->translate(5, 50);
344         canvas->drawPath(fVisualizerPath, paint);
345     }
346 
347 private:
348     typedef skiagm::GM INHERITED;
349 };
350 
351 // test inverse-fill w/ a clip that completely excludes the geometry
352 class PathInverseFillGM : public skiagm::GM {
353     SkPath  fPath[N];
354     SkScalar fDY[N];
355 protected:
onOnceBeforeDraw()356     void onOnceBeforeDraw() override {
357         for (size_t i = 0; i < N; i++) {
358             fDY[i] = gProcs[i](&fPath[i]);
359         }
360     }
361 
onShortName()362     SkString onShortName() override {
363         return SkString("pathinvfill");
364     }
365 
onISize()366     SkISize onISize() override {
367         return SkISize::Make(450, 220);
368     }
369 
show(SkCanvas * canvas,const SkPath & path,const SkPaint & paint,const SkRect * clip,SkScalar top,const SkScalar bottom)370     static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint,
371                      const SkRect* clip, SkScalar top, const SkScalar bottom) {
372         canvas->save();
373         if (clip) {
374             SkRect r = *clip;
375             r.fTop = top;
376             r.fBottom = bottom;
377             canvas->clipRect(r);
378         }
379         canvas->drawPath(path, paint);
380         canvas->restore();
381     }
382 
onDraw(SkCanvas * canvas)383     void onDraw(SkCanvas* canvas) override {
384         SkPath path;
385 
386         path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40));
387         path.toggleInverseFillType();
388 
389         SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) };
390 
391         canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
392 
393         for (int doclip = 0; doclip <= 1; ++doclip) {
394             for (int aa = 0; aa <= 1; ++aa) {
395                 SkPaint paint;
396                 paint.setAntiAlias(SkToBool(aa));
397 
398                 canvas->save();
399                 canvas->clipRect(clipR);
400 
401                 const SkRect* clipPtr = doclip ? &clipR : nullptr;
402 
403                 show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY());
404                 show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom);
405 
406                 canvas->restore();
407                 canvas->translate(SkIntToScalar(110), 0);
408             }
409         }
410     }
411 
412 private:
413     typedef skiagm::GM INHERITED;
414 };
415 
416 DEF_SIMPLE_GM(rotatedcubicpath, canvas, 200, 200) {
417     SkPaint p;
418     p.setAntiAlias(true);
419     p.setStyle(SkPaint::kFill_Style);
420 
421     canvas->translate(50, 50);
422     SkPath path;
423     path.moveTo(48,-23);
424     path.cubicTo(48,-29.5, 6,-30, 6,-30);
425     path.cubicTo(6,-30, 2,0, 2,0);
426     path.cubicTo(2,0, 44,-21.5, 48,-23);
427     path.close();
428 
429     p.setColor(SK_ColorBLUE);
430     canvas->drawPath(path, p);
431 
432     // Rotated path, which is not antialiased on GPU
433     p.setColor(SK_ColorRED);
434     canvas->rotate(90);
435     canvas->drawPath(path, p);
436 }
437 
438 ///////////////////////////////////////////////////////////////////////////////
439 
440 DEF_GM( return new PathFillGM; )
DEF_GM(return new PathInverseFillGM;)441 DEF_GM( return new PathInverseFillGM; )
442 
443 DEF_SIMPLE_GM(bug7792, canvas, 800, 800) {
444     // from skbug.com/7792 bug description
445     SkPaint p;
446     SkPath path;
447     path.moveTo(10, 10);
448     path.moveTo(75, 75);
449     path.lineTo(150, 75);
450     path.lineTo(150, 150);
451     path.lineTo(75, 150);
452     canvas->drawPath(path, p);
453     // from skbug.com/7792#c3
454     canvas->translate(200, 0);
455     path.reset();
456     path.moveTo(75, 50);
457     path.moveTo(100, 75);
458     path.lineTo(150, 75);
459     path.lineTo(150, 150);
460     path.lineTo(75, 150);
461     path.lineTo(75, 50);
462     path.close();
463     canvas->drawPath(path, p);
464     // from skbug.com/7792#c9
465     canvas->translate(200, 0);
466     path.reset();
467     path.moveTo(10, 10);
468     path.moveTo(75, 75);
469     path.lineTo(150, 75);
470     path.lineTo(150, 150);
471     path.lineTo(75, 150);
472     path.close();
473     canvas->drawPath(path, p);
474     // from skbug.com/7792#c11
475     canvas->translate(-200 * 2, 200);
476     path.reset();
477     path.moveTo(75, 150);
478     path.lineTo(75, 75);
479     path.lineTo(150, 75);
480     path.lineTo(150, 150);
481     path.lineTo(75, 150);
482     path.moveTo(75, 150);
483     canvas->drawPath(path, p);
484     // from skbug.com/7792#c14
485     canvas->translate(200, 0);
486     path.reset();
487     path.moveTo(250, 75);
488     path.moveTo(250, 75);
489     path.moveTo(250, 75);
490     path.moveTo(100, 75);
491     path.lineTo(150, 75);
492     path.lineTo(150, 150);
493     path.lineTo(75, 150);
494     path.lineTo(75, 75);
495     path.close();
496     path.lineTo(0, 0);
497     path.close();
498     canvas->drawPath(path, p);
499     // from skbug.com/7792#c15
500     canvas->translate(200, 0);
501     path.reset();
502     path.moveTo(75, 75);
503     path.lineTo(150, 75);
504     path.lineTo(150, 150);
505     path.lineTo(75, 150);
506     path.moveTo(250, 75);
507     canvas->drawPath(path, p);
508     // from skbug.com/7792#c17
509     canvas->translate(-200 * 2, 200);
510     path.reset();
511     path.moveTo(75, 10);
512     path.moveTo(75, 75);
513     path.lineTo(150, 75);
514     path.lineTo(150, 150);
515     path.lineTo(75, 150);
516     path.lineTo(75, 10);
517     path.close();
518     canvas->drawPath(path, p);
519     // from skbug.com/7792#c19
520     canvas->translate(200, 0);
521     path.reset();
522     path.moveTo(75, 75);
523     path.lineTo(75, 75);
524     path.lineTo(75, 75);
525     path.lineTo(75, 75);
526     path.lineTo(150, 75);
527     path.lineTo(150, 150);
528     path.lineTo(75, 150);
529     path.close();
530     path.moveTo(10, 10);
531     path.lineTo(30, 10);
532     path.lineTo(10, 30);
533     canvas->drawPath(path, p);
534     // from skbug.com/7792#c23
535     canvas->translate(200, 0);
536     path.reset();
537     path.moveTo(75, 75);
538     path.lineTo(75, 75);
539     path.moveTo(75, 75);
540     path.lineTo(75, 75);
541     path.lineTo(150, 75);
542     path.lineTo(150, 150);
543     path.lineTo(75, 150);
544     path.close();
545     canvas->drawPath(path, p);
546     // from skbug.com/7792#c29
547     canvas->translate(-200 * 2, 200);
548     path.reset();
549     path.moveTo(75, 75);
550     path.lineTo(150, 75);
551     path.lineTo(150, 150);
552     path.lineTo(75, 150);
553     path.lineTo(75, 250);
554     path.moveTo(75, 75);
555     path.close();
556     canvas->drawPath(path, p);
557     // from skbug.com/7792#c31
558     canvas->translate(200, 0);
559     path.reset();
560     path.moveTo(75, 75);
561     path.lineTo(150, 75);
562     path.lineTo(150, 150);
563     path.lineTo(75, 150);
564     path.lineTo(75, 10);
565     path.moveTo(75, 75);
566     path.close();
567     canvas->drawPath(path, p);
568     // from skbug.com/7792#c36
569     canvas->translate(200, 0);
570     path.reset();
571     path.moveTo(75, 75);
572     path.lineTo(150, 75);
573     path.lineTo(150, 150);
574     path.lineTo(10, 150);
575     path.moveTo(75, 75);
576     path.lineTo(75, 75);
577     canvas->drawPath(path, p);
578     // from skbug.com/7792#c39
579     canvas->translate(200, -200 * 3);
580     path.reset();
581     path.moveTo(150, 75);
582     path.lineTo(150, 150);
583     path.lineTo(75, 150);
584     path.lineTo(75, 100);
585     canvas->drawPath(path, p);
586     // from zero_length_paths_aa
587     canvas->translate(0, 200);
588     path.reset();
589     path.moveTo(150, 100);
590     path.lineTo(150, 100);
591     path.lineTo(150, 150);
592     path.lineTo(75, 150);
593     path.lineTo(75, 100);
594     path.lineTo(75, 75);
595     path.lineTo(150, 75);
596     path.close();
597     canvas->drawPath(path, p);
598     // from skbug.com/7792#c41
599     canvas->translate(0, 200);
600     path.reset();
601     path.moveTo(75, 75);
602     path.lineTo(150, 75);
603     path.lineTo(150, 150);
604     path.lineTo(140, 150);
605     path.lineTo(140, 75);
606     path.moveTo(75, 75);
607     path.close();
608     canvas->drawPath(path, p);
609     // from skbug.com/7792#c53
610     canvas->translate(0, 200);
611     path.reset();
612     path.moveTo(75, 75);
613     path.lineTo(150, 75);
614     path.lineTo(150, 150);
615     path.lineTo(140, 150);
616     path.lineTo(140, 75);
617     path.moveTo(75, 75);
618     path.close();
619     canvas->drawPath(path, p);
620 }
621