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 "SkCanvas.h"
9#include "SkPaint.h"
10#include "SkRandom.h"
11
12// skbug.com/1316 shows that this cubic, when slightly clipped, creates big
13// (incorrect) changes to its control points.
14class ClippedCubicGM : public skiagm::GM {
15public:
16    ClippedCubicGM() {}
17
18protected:
19    SkString onShortName() {
20        return SkString("clippedcubic");
21    }
22
23    SkISize onISize() { return SkISize::Make(1240, 390); }
24
25    virtual void onDraw(SkCanvas* canvas) {
26        SkPath path;
27        path.moveTo(0, 0);
28        path.cubicTo(140, 150, 40, 10, 170, 150);
29
30        SkPaint paint;
31        SkRect bounds = path.getBounds();
32
33        for (SkScalar dy = -1; dy <= 1; dy += 1) {
34            canvas->save();
35            for (SkScalar dx = -1; dx <= 1; dx += 1) {
36                canvas->save();
37                canvas->clipRect(bounds);
38                canvas->translate(dx, dy);
39                canvas->drawPath(path, paint);
40                canvas->restore();
41
42                canvas->translate(bounds.width(), 0);
43            }
44            canvas->restore();
45            canvas->translate(0, bounds.height());
46        }
47    }
48
49private:
50    typedef skiagm::GM INHERITED;
51};
52
53class CubicPathGM : public skiagm::GM {
54public:
55    CubicPathGM() {}
56
57protected:
58    SkString onShortName() {
59        return SkString("cubicpath");
60    }
61
62    SkISize onISize() { return SkISize::Make(1240, 390); }
63
64    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
65                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
66                  SkPaint::Style style, SkPath::FillType fill,
67                  SkScalar strokeWidth) {
68        path.setFillType(fill);
69        SkPaint paint;
70        paint.setStrokeCap(cap);
71        paint.setStrokeWidth(strokeWidth);
72        paint.setStrokeJoin(join);
73        paint.setColor(color);
74        paint.setStyle(style);
75        canvas->save();
76        canvas->clipRect(clip);
77        canvas->drawPath(path, paint);
78        canvas->restore();
79    }
80
81    virtual void onDraw(SkCanvas* canvas) {
82        struct FillAndName {
83            SkPath::FillType fFill;
84            const char*      fName;
85        };
86        static const FillAndName gFills[] = {
87            {SkPath::kWinding_FillType, "Winding"},
88            {SkPath::kEvenOdd_FillType, "Even / Odd"},
89            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
90            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
91        };
92        struct StyleAndName {
93            SkPaint::Style fStyle;
94            const char*    fName;
95        };
96        static const StyleAndName gStyles[] = {
97            {SkPaint::kFill_Style, "Fill"},
98            {SkPaint::kStroke_Style, "Stroke"},
99            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
100        };
101        struct CapAndName {
102            SkPaint::Cap  fCap;
103            SkPaint::Join fJoin;
104            const char*   fName;
105        };
106        static const CapAndName gCaps[] = {
107            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
108            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
109            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
110        };
111        struct PathAndName {
112            SkPath      fPath;
113            const char* fName;
114        };
115        PathAndName path;
116        path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
117        path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
118                           60*SK_Scalar1, 20*SK_Scalar1,
119                           75*SK_Scalar1, 10*SK_Scalar1);
120        path.fName = "moveTo-cubic";
121
122        SkPaint titlePaint;
123        titlePaint.setColor(SK_ColorBLACK);
124        titlePaint.setAntiAlias(true);
125        titlePaint.setLCDRenderText(true);
126        titlePaint.setTextSize(15 * SK_Scalar1);
127        const char title[] = "Cubic Drawn Into Rectangle Clips With "
128                             "Indicated Style, Fill and Linecaps, with stroke width 10";
129        canvas->drawText(title, strlen(title),
130                            20 * SK_Scalar1,
131                            20 * SK_Scalar1,
132                            titlePaint);
133
134        SkRandom rand;
135        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
136        canvas->save();
137        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
138        canvas->save();
139        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
140            if (0 < cap) {
141                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
142            }
143            canvas->save();
144            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
145                if (0 < fill) {
146                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
147                }
148                canvas->save();
149                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
150                    if (0 < style) {
151                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
152                    }
153
154                    SkColor color = 0xff007000;
155                    this->drawPath(path.fPath, canvas, color, rect,
156                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
157                                    gFills[fill].fFill, SK_Scalar1*10);
158
159                    SkPaint rectPaint;
160                    rectPaint.setColor(SK_ColorBLACK);
161                    rectPaint.setStyle(SkPaint::kStroke_Style);
162                    rectPaint.setStrokeWidth(-1);
163                    rectPaint.setAntiAlias(true);
164                    canvas->drawRect(rect, rectPaint);
165
166                    SkPaint labelPaint;
167                    labelPaint.setColor(color);
168                    labelPaint.setAntiAlias(true);
169                    labelPaint.setLCDRenderText(true);
170                    labelPaint.setTextSize(10 * SK_Scalar1);
171                    canvas->drawText(gStyles[style].fName,
172                                        strlen(gStyles[style].fName),
173                                        0, rect.height() + 12 * SK_Scalar1,
174                                        labelPaint);
175                    canvas->drawText(gFills[fill].fName,
176                                        strlen(gFills[fill].fName),
177                                        0, rect.height() + 24 * SK_Scalar1,
178                                        labelPaint);
179                    canvas->drawText(gCaps[cap].fName,
180                                        strlen(gCaps[cap].fName),
181                                        0, rect.height() + 36 * SK_Scalar1,
182                                        labelPaint);
183                }
184                canvas->restore();
185            }
186            canvas->restore();
187        }
188        canvas->restore();
189        canvas->restore();
190    }
191
192private:
193    typedef skiagm::GM INHERITED;
194};
195
196class CubicClosePathGM : public skiagm::GM {
197public:
198    CubicClosePathGM() {}
199
200protected:
201    SkString onShortName() {
202        return SkString("cubicclosepath");
203    }
204
205    SkISize onISize() { return SkISize::Make(1240, 390); }
206
207    void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
208                  const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
209                  SkPaint::Style style, SkPath::FillType fill,
210                  SkScalar strokeWidth) {
211        path.setFillType(fill);
212        SkPaint paint;
213        paint.setStrokeCap(cap);
214        paint.setStrokeWidth(strokeWidth);
215        paint.setStrokeJoin(join);
216        paint.setColor(color);
217        paint.setStyle(style);
218        canvas->save();
219        canvas->clipRect(clip);
220        canvas->drawPath(path, paint);
221        canvas->restore();
222    }
223
224    virtual void onDraw(SkCanvas* canvas) {
225        struct FillAndName {
226            SkPath::FillType fFill;
227            const char*      fName;
228        };
229        static const FillAndName gFills[] = {
230            {SkPath::kWinding_FillType, "Winding"},
231            {SkPath::kEvenOdd_FillType, "Even / Odd"},
232            {SkPath::kInverseWinding_FillType, "Inverse Winding"},
233            {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
234        };
235        struct StyleAndName {
236            SkPaint::Style fStyle;
237            const char*    fName;
238        };
239        static const StyleAndName gStyles[] = {
240            {SkPaint::kFill_Style, "Fill"},
241            {SkPaint::kStroke_Style, "Stroke"},
242            {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
243        };
244        struct CapAndName {
245            SkPaint::Cap  fCap;
246            SkPaint::Join fJoin;
247            const char*   fName;
248        };
249        static const CapAndName gCaps[] = {
250            {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
251            {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
252            {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
253        };
254        struct PathAndName {
255            SkPath      fPath;
256            const char* fName;
257        };
258        PathAndName path;
259        path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
260        path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
261                           60*SK_Scalar1, 20*SK_Scalar1,
262                           75*SK_Scalar1, 10*SK_Scalar1);
263        path.fPath.close();
264        path.fName = "moveTo-cubic-close";
265
266        SkPaint titlePaint;
267        titlePaint.setColor(SK_ColorBLACK);
268        titlePaint.setAntiAlias(true);
269        titlePaint.setLCDRenderText(true);
270        titlePaint.setTextSize(15 * SK_Scalar1);
271        const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
272                             "Indicated Style, Fill and Linecaps, with stroke width 10";
273        canvas->drawText(title, strlen(title),
274                            20 * SK_Scalar1,
275                            20 * SK_Scalar1,
276                            titlePaint);
277
278        SkRandom rand;
279        SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
280        canvas->save();
281        canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
282        canvas->save();
283        for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
284            if (0 < cap) {
285                canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
286            }
287            canvas->save();
288            for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
289                if (0 < fill) {
290                    canvas->translate(0, rect.height() + 40 * SK_Scalar1);
291                }
292                canvas->save();
293                for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
294                    if (0 < style) {
295                        canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
296                    }
297
298                    SkColor color = 0xff007000;
299                    this->drawPath(path.fPath, canvas, color, rect,
300                                    gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
301                                    gFills[fill].fFill, SK_Scalar1*10);
302
303                    SkPaint rectPaint;
304                    rectPaint.setColor(SK_ColorBLACK);
305                    rectPaint.setStyle(SkPaint::kStroke_Style);
306                    rectPaint.setStrokeWidth(-1);
307                    rectPaint.setAntiAlias(true);
308                    canvas->drawRect(rect, rectPaint);
309
310                    SkPaint labelPaint;
311                    labelPaint.setColor(color);
312                    labelPaint.setAntiAlias(true);
313                    labelPaint.setLCDRenderText(true);
314                    labelPaint.setTextSize(10 * SK_Scalar1);
315                    canvas->drawText(gStyles[style].fName,
316                                        strlen(gStyles[style].fName),
317                                        0, rect.height() + 12 * SK_Scalar1,
318                                        labelPaint);
319                    canvas->drawText(gFills[fill].fName,
320                                        strlen(gFills[fill].fName),
321                                        0, rect.height() + 24 * SK_Scalar1,
322                                        labelPaint);
323                    canvas->drawText(gCaps[cap].fName,
324                                        strlen(gCaps[cap].fName),
325                                        0, rect.height() + 36 * SK_Scalar1,
326                                        labelPaint);
327                }
328                canvas->restore();
329            }
330            canvas->restore();
331        }
332        canvas->restore();
333        canvas->restore();
334    }
335
336private:
337    typedef skiagm::GM INHERITED;
338};
339
340//////////////////////////////////////////////////////////////////////////////
341
342DEF_GM( return new CubicPathGM; )
343DEF_GM( return new CubicClosePathGM; )
344DEF_GM( return new ClippedCubicGM; )
345