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     static const 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)53 static SkScalar make_sawtooth(SkPath* path) {
54     SkScalar x = SkIntToScalar(20);
55     SkScalar y = SkIntToScalar(20);
56     const SkScalar x0 = x;
57     const SkScalar dx = SK_Scalar1 * 5;
58     const SkScalar dy = SK_Scalar1 * 10;
59 
60     path->moveTo(x, y);
61     for (int i = 0; i < 32; 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_star(SkPath * path,int n)73 static SkScalar make_star(SkPath* path, int n) {
74     const SkScalar c = SkIntToScalar(45);
75     const SkScalar r = SkIntToScalar(20);
76 
77     SkScalar rad = -SK_ScalarPI / 2;
78     const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;
79 
80     path->moveTo(c, c - r);
81     for (int i = 1; i < n; i++) {
82         rad += drad;
83         SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
84         path->lineTo(c + SkScalarMul(cosV, r), c + SkScalarMul(sinV, r));
85     }
86     path->close();
87     return r * 2 * 6 / 5;
88 }
89 
make_star_5(SkPath * path)90 static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
make_star_13(SkPath * path)91 static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
92 
93 // We don't expect any output from this path.
make_line(SkPath * path)94 static SkScalar make_line(SkPath* path) {
95     path->moveTo(SkIntToScalar(30), SkIntToScalar(30));
96     path->lineTo(SkIntToScalar(120), SkIntToScalar(40));
97     path->close();
98     path->moveTo(SkIntToScalar(150), SkIntToScalar(30));
99     path->lineTo(SkIntToScalar(150), SkIntToScalar(30));
100     path->lineTo(SkIntToScalar(300), SkIntToScalar(40));
101     path->close();
102     return SkIntToScalar(40);
103 }
104 
105 static const MakePathProc gProcs[] = {
106     make_frame,
107     make_triangle,
108     make_rect,
109     make_oval,
110     make_sawtooth,
111     make_star_5,
112     make_star_13,
113     make_line,
114 };
115 
116 #define N   SK_ARRAY_COUNT(gProcs)
117 
118 class PathFillGM : public skiagm::GM {
119     SkPath  fPath[N];
120     SkScalar fDY[N];
121 protected:
onOnceBeforeDraw()122     void onOnceBeforeDraw() override {
123         for (size_t i = 0; i < N; i++) {
124             fDY[i] = gProcs[i](&fPath[i]);
125         }
126     }
127 
128 
onShortName()129     SkString onShortName() override {
130         return SkString("pathfill");
131     }
132 
onISize()133     SkISize onISize() override {
134         return SkISize::Make(640, 480);
135     }
136 
onDraw(SkCanvas * canvas)137     void onDraw(SkCanvas* canvas) override {
138         SkPaint paint;
139         paint.setAntiAlias(true);
140 
141         for (size_t i = 0; i < N; i++) {
142             canvas->drawPath(fPath[i], paint);
143             canvas->translate(SkIntToScalar(0), fDY[i]);
144         }
145     }
146 
147 private:
148     typedef skiagm::GM INHERITED;
149 };
150 
151 // test inverse-fill w/ a clip that completely excludes the geometry
152 class PathInverseFillGM : public skiagm::GM {
153     SkPath  fPath[N];
154     SkScalar fDY[N];
155 protected:
onOnceBeforeDraw()156     void onOnceBeforeDraw() override {
157         for (size_t i = 0; i < N; i++) {
158             fDY[i] = gProcs[i](&fPath[i]);
159         }
160     }
161 
onShortName()162     SkString onShortName() override {
163         return SkString("pathinvfill");
164     }
165 
onISize()166     SkISize onISize() override {
167         return SkISize::Make(450, 220);
168     }
169 
show(SkCanvas * canvas,const SkPath & path,const SkPaint & paint,const SkRect * clip,SkScalar top,const SkScalar bottom)170     static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint,
171                      const SkRect* clip, SkScalar top, const SkScalar bottom) {
172         canvas->save();
173         if (clip) {
174             SkRect r = *clip;
175             r.fTop = top;
176             r.fBottom = bottom;
177             canvas->clipRect(r);
178         }
179         canvas->drawPath(path, paint);
180         canvas->restore();
181     }
182 
onDraw(SkCanvas * canvas)183     void onDraw(SkCanvas* canvas) override {
184         SkPath path;
185 
186         path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40));
187         path.toggleInverseFillType();
188 
189         SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) };
190 
191         canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
192 
193         for (int doclip = 0; doclip <= 1; ++doclip) {
194             for (int aa = 0; aa <= 1; ++aa) {
195                 SkPaint paint;
196                 paint.setAntiAlias(SkToBool(aa));
197 
198                 canvas->save();
199                 canvas->clipRect(clipR);
200 
201                 const SkRect* clipPtr = doclip ? &clipR : nullptr;
202 
203                 show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY());
204                 show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom);
205 
206                 canvas->restore();
207                 canvas->translate(SkIntToScalar(110), 0);
208             }
209         }
210     }
211 
212 private:
213     typedef skiagm::GM INHERITED;
214 };
215 
216 ///////////////////////////////////////////////////////////////////////////////
217 
218 DEF_GM( return new PathFillGM; )
219 DEF_GM( return new PathInverseFillGM; )
220