pathfill.cpp revision 7704754049cac4794f27496efa90acea963b8881
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
11typedef SkScalar (*MakePathProc)(SkPath*);
12
13static 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
25static 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
37static 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
45static 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
53static 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
73static SkScalar make_sawtooth_3(SkPath* path) { return make_sawtooth(path, 3); }
74static SkScalar make_sawtooth_32(SkPath* path) { return make_sawtooth(path, 32); }
75
76static 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
111static 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 + SkScalarMul(cosV, r), c + SkScalarMul(sinV, r));
123    }
124    path->close();
125    return r * 2 * 6 / 5;
126}
127
128static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
129static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
130
131// We don't expect any output from this path.
132static 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
143static SkScalar 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    return SkIntToScalar(44);
184}
185
186constexpr MakePathProc gProcs[] = {
187    make_frame,
188    make_triangle,
189    make_rect,
190    make_oval,
191    make_sawtooth_32,
192    make_star_5,
193    make_star_13,
194    make_line,
195    make_house,
196    make_sawtooth_3,
197};
198
199#define N   SK_ARRAY_COUNT(gProcs)
200
201class PathFillGM : public skiagm::GM {
202    SkPath  fPath[N];
203    SkScalar fDY[N];
204    SkPath  fInfoPath;
205protected:
206    void onOnceBeforeDraw() override {
207        for (size_t i = 0; i < N; i++) {
208            fDY[i] = gProcs[i](&fPath[i]);
209        }
210
211        (void) make_info(&fInfoPath);
212    }
213
214
215    SkString onShortName() override {
216        return SkString("pathfill");
217    }
218
219    SkISize onISize() override {
220        return SkISize::Make(640, 480);
221    }
222
223    void onDraw(SkCanvas* canvas) override {
224        SkPaint paint;
225        paint.setAntiAlias(true);
226
227        for (size_t i = 0; i < N; i++) {
228            canvas->drawPath(fPath[i], paint);
229            canvas->translate(SkIntToScalar(0), fDY[i]);
230        }
231
232        canvas->scale(0.300000011920929f, 0.300000011920929f);
233        canvas->translate(50, 50);
234        canvas->drawPath(fInfoPath, paint);
235    }
236
237private:
238    typedef skiagm::GM INHERITED;
239};
240
241// test inverse-fill w/ a clip that completely excludes the geometry
242class PathInverseFillGM : public skiagm::GM {
243    SkPath  fPath[N];
244    SkScalar fDY[N];
245protected:
246    void onOnceBeforeDraw() override {
247        for (size_t i = 0; i < N; i++) {
248            fDY[i] = gProcs[i](&fPath[i]);
249        }
250    }
251
252    SkString onShortName() override {
253        return SkString("pathinvfill");
254    }
255
256    SkISize onISize() override {
257        return SkISize::Make(450, 220);
258    }
259
260    static void show(SkCanvas* canvas, const SkPath& path, const SkPaint& paint,
261                     const SkRect* clip, SkScalar top, const SkScalar bottom) {
262        canvas->save();
263        if (clip) {
264            SkRect r = *clip;
265            r.fTop = top;
266            r.fBottom = bottom;
267            canvas->clipRect(r);
268        }
269        canvas->drawPath(path, paint);
270        canvas->restore();
271    }
272
273    void onDraw(SkCanvas* canvas) override {
274        SkPath path;
275
276        path.addCircle(SkIntToScalar(50), SkIntToScalar(50), SkIntToScalar(40));
277        path.toggleInverseFillType();
278
279        SkRect clipR = { 0, 0, SkIntToScalar(100), SkIntToScalar(200) };
280
281        canvas->translate(SkIntToScalar(10), SkIntToScalar(10));
282
283        for (int doclip = 0; doclip <= 1; ++doclip) {
284            for (int aa = 0; aa <= 1; ++aa) {
285                SkPaint paint;
286                paint.setAntiAlias(SkToBool(aa));
287
288                canvas->save();
289                canvas->clipRect(clipR);
290
291                const SkRect* clipPtr = doclip ? &clipR : nullptr;
292
293                show(canvas, path, paint, clipPtr, clipR.fTop, clipR.centerY());
294                show(canvas, path, paint, clipPtr, clipR.centerY(), clipR.fBottom);
295
296                canvas->restore();
297                canvas->translate(SkIntToScalar(110), 0);
298            }
299        }
300    }
301
302private:
303    typedef skiagm::GM INHERITED;
304};
305
306DEF_SIMPLE_GM(rotatedcubicpath, canvas, 200, 200) {
307    SkPaint p;
308    p.setAntiAlias(true);
309    p.setStyle(SkPaint::kFill_Style);
310
311    canvas->translate(50, 50);
312    SkPath path;
313    path.moveTo(48,-23);
314    path.cubicTo(48,-29.5, 6,-30, 6,-30);
315    path.cubicTo(6,-30, 2,0, 2,0);
316    path.cubicTo(2,0, 44,-21.5, 48,-23);
317    path.close();
318
319    p.setColor(SK_ColorBLUE);
320    canvas->drawPath(path, p);
321
322    // Rotated path, which is not antialiased on GPU
323    p.setColor(SK_ColorRED);
324    canvas->rotate(90);
325    canvas->drawPath(path, p);
326}
327
328///////////////////////////////////////////////////////////////////////////////
329
330DEF_GM( return new PathFillGM; )
331DEF_GM( return new PathInverseFillGM; )
332