pathfill.cpp revision e3e8c727413f9473e139b69d43f89b8884e732d7
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    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
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) {
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
73static 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
90static SkScalar make_star_5(SkPath* path) { return make_star(path, 5); }
91static SkScalar make_star_13(SkPath* path) { return make_star(path, 13); }
92
93// We don't expect any output from this path.
94static 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
105static 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
118class PathFillGM : public skiagm::GM {
119    SkPath  fPath[N];
120    SkScalar fDY[N];
121protected:
122    void onOnceBeforeDraw() override {
123        for (size_t i = 0; i < N; i++) {
124            fDY[i] = gProcs[i](&fPath[i]);
125        }
126    }
127
128
129    SkString onShortName() override {
130        return SkString("pathfill");
131    }
132
133    SkISize onISize() override {
134        return SkISize::Make(640, 480);
135    }
136
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
147private:
148    typedef skiagm::GM INHERITED;
149};
150
151// test inverse-fill w/ a clip that completely excludes the geometry
152class PathInverseFillGM : public skiagm::GM {
153    SkPath  fPath[N];
154    SkScalar fDY[N];
155protected:
156    void onOnceBeforeDraw() override {
157        for (size_t i = 0; i < N; i++) {
158            fDY[i] = gProcs[i](&fPath[i]);
159        }
160    }
161
162    SkString onShortName() override {
163        return SkString("pathinvfill");
164    }
165
166    SkISize onISize() override {
167        return SkISize::Make(450, 220);
168    }
169
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
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
212private:
213    typedef skiagm::GM INHERITED;
214};
215
216DEF_SIMPLE_GM(rotatedcubicpath, canvas, 200, 200) {
217    SkPaint p;
218    p.setAntiAlias(true);
219    p.setStyle(SkPaint::kFill_Style);
220
221    canvas->translate(50, 50);
222    SkPath path;
223    path.moveTo(48,-23);
224    path.cubicTo(48,-29.5, 6,-30, 6,-30);
225    path.cubicTo(6,-30, 2,0, 2,0);
226    path.cubicTo(2,0, 44,-21.5, 48,-23);
227    path.close();
228
229    p.setColor(SK_ColorBLUE);
230    canvas->drawPath(path, p);
231
232    // Rotated path, which is not antialiased on GPU
233    p.setColor(SK_ColorRED);
234    canvas->rotate(90);
235    canvas->drawPath(path, p);
236}
237
238///////////////////////////////////////////////////////////////////////////////
239
240DEF_GM( return new PathFillGM; )
241DEF_GM( return new PathInverseFillGM; )
242