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#include "gm.h"
8#include "sk_tool_utils.h"
9#include "SkCanvas.h"
10#include "SkPaint.h"
11#include "SkPath.h"
12#include "SkRandom.h"
13
14namespace skiagm {
15
16class EmptyPathGM : public GM {
17public:
18    EmptyPathGM() {}
19
20protected:
21    SkString onShortName() {
22        return SkString("emptypath");
23    }
24
25    SkISize onISize() { return SkISize::Make(600, 280); }
26
27    void drawEmpty(SkCanvas* canvas,
28                    SkColor color,
29                    const SkRect& clip,
30                    SkPaint::Style style,
31                    SkPath::FillType fill) {
32        SkPath path;
33        path.setFillType(fill);
34        SkPaint paint;
35        paint.setColor(color);
36        paint.setStyle(style);
37        canvas->save();
38        canvas->clipRect(clip);
39        canvas->drawPath(path, paint);
40        canvas->restore();
41    }
42
43    virtual void onDraw(SkCanvas* canvas) {
44        struct FillAndName {
45            SkPath::FillType fFill;
46            const char*      fName;
47        };
48        constexpr FillAndName gFills[] = {
49            {SkPath::kWinding_FillType, "Winding"},
50            {SkPath::kEvenOdd_FillType, "Even / Odd"},
51            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
52            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
53        };
54        struct StyleAndName {
55            SkPaint::Style fStyle;
56            const char*    fName;
57        };
58        constexpr StyleAndName gStyles[] = {
59            {SkPaint::kFill_Style, "Fill"},
60            {SkPaint::kStroke_Style, "Stroke"},
61            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
62        };
63
64        SkPaint titlePaint;
65        titlePaint.setColor(SK_ColorBLACK);
66        titlePaint.setAntiAlias(true);
67        sk_tool_utils::set_portable_typeface(&titlePaint);
68        titlePaint.setTextSize(15 * SK_Scalar1);
69        const char title[] = "Empty Paths Drawn Into Rectangle Clips With "
70                             "Indicated Style and Fill";
71        canvas->drawString(title,
72                           20 * SK_Scalar1,
73                           20 * SK_Scalar1,
74                           titlePaint);
75
76        SkRandom rand;
77        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
78        int i = 0;
79        canvas->save();
80        canvas->translate(10 * SK_Scalar1, 0);
81        canvas->save();
82        for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
83            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
84                if (0 == i % 4) {
85                    canvas->restore();
86                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
87                    canvas->save();
88                } else {
89                    canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
90                }
91                ++i;
92
93
94                SkColor color = rand.nextU();
95                color = 0xff000000 | color; // force solid
96                color = sk_tool_utils::color_to_565(color);
97                this->drawEmpty(canvas, color, rect,
98                                gStyles[style].fStyle, gFills[fill].fFill);
99
100                SkPaint rectPaint;
101                rectPaint.setColor(SK_ColorBLACK);
102                rectPaint.setStyle(SkPaint::kStroke_Style);
103                rectPaint.setStrokeWidth(-1);
104                rectPaint.setAntiAlias(true);
105                canvas->drawRect(rect, rectPaint);
106
107                SkPaint labelPaint;
108                labelPaint.setColor(color);
109                labelPaint.setAntiAlias(true);
110                sk_tool_utils::set_portable_typeface(&labelPaint);
111                labelPaint.setTextSize(12 * SK_Scalar1);
112                canvas->drawString(gStyles[style].fName,
113                                   0, rect.height() + 15 * SK_Scalar1,
114                                   labelPaint);
115                canvas->drawString(gFills[fill].fName,
116                                   0, rect.height() + 28 * SK_Scalar1,
117                                   labelPaint);
118            }
119        }
120        canvas->restore();
121        canvas->restore();
122    }
123
124private:
125    typedef GM INHERITED;
126};
127DEF_GM( return new EmptyPathGM; )
128
129//////////////////////////////////////////////////////////////////////////////
130
131static void make_path_move(SkPath* path, const SkPoint pts[3]) {
132    for (int i = 0; i < 3; ++i) {
133        path->moveTo(pts[i]);
134    }
135}
136
137static void make_path_move_close(SkPath* path, const SkPoint pts[3]) {
138    for (int i = 0; i < 3; ++i) {
139        path->moveTo(pts[i]);
140        path->close();
141    }
142}
143
144static void make_path_move_line(SkPath* path, const SkPoint pts[3]) {
145    for (int i = 0; i < 3; ++i) {
146        path->moveTo(pts[i]);
147        path->lineTo(pts[i]);
148    }
149}
150
151typedef void (*MakePathProc)(SkPath*, const SkPoint pts[3]);
152
153static void make_path_move_mix(SkPath* path, const SkPoint pts[3]) {
154    path->moveTo(pts[0]);
155    path->moveTo(pts[1]); path->close();
156    path->moveTo(pts[2]); path->lineTo(pts[2]);
157}
158
159class EmptyStrokeGM : public GM {
160    SkPoint fPts[3];
161
162public:
163    EmptyStrokeGM() {
164        fPts[0].set(40, 40);
165        fPts[1].set(80, 40);
166        fPts[2].set(120, 40);
167    }
168
169protected:
170    SkString onShortName() override {
171        return SkString("emptystroke");
172    }
173
174    SkISize onISize() override { return SkISize::Make(200, 240); }
175
176    void onDraw(SkCanvas* canvas) override {
177        const MakePathProc procs[] = {
178            make_path_move,             // expect red red red
179            make_path_move_close,       // expect black black black
180            make_path_move_line,        // expect black black black
181            make_path_move_mix,         // expect red black black,
182        };
183
184        SkPaint strokePaint;
185        strokePaint.setStyle(SkPaint::kStroke_Style);
186        strokePaint.setStrokeWidth(21);
187        strokePaint.setStrokeCap(SkPaint::kSquare_Cap);
188
189        SkPaint dotPaint;
190        dotPaint.setColor(SK_ColorRED);
191        strokePaint.setStyle(SkPaint::kStroke_Style);
192        dotPaint.setStrokeWidth(7);
193
194        for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
195            SkPath path;
196            procs[i](&path, fPts);
197            canvas->drawPoints(SkCanvas::kPoints_PointMode, 3, fPts, dotPaint);
198            canvas->drawPath(path, strokePaint);
199            canvas->translate(0, 40);
200        }
201    }
202
203private:
204    typedef GM INHERITED;
205};
206DEF_GM( return new EmptyStrokeGM; )
207
208}
209