1
2/*
3 * Copyright 2013 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "gm.h"
10#include "SkTArray.h"
11#include "SkRandom.h"
12#include "SkMatrix.h"
13#include "SkBlurMaskFilter.h"
14#include "SkGradientShader.h"
15#include "SkBlurDrawLooper.h"
16#include "SkRect.h"
17#include "SkRRect.h"
18
19namespace skiagm {
20
21class RoundRectGM : public GM {
22public:
23    RoundRectGM() {
24        this->setBGColor(0xFF000000);
25        this->makePaints();
26        this->makeMatrices();
27    }
28
29protected:
30
31    SkString onShortName() override {
32        return SkString("roundrects");
33    }
34
35    SkISize onISize() override {
36        return SkISize::Make(1200, 900);
37    }
38
39    void makePaints() {
40        {
41        // no AA
42        SkPaint p;
43        fPaints.push_back(p);
44        }
45
46        {
47        // AA
48        SkPaint p;
49        p.setAntiAlias(true);
50        fPaints.push_back(p);
51        }
52
53        {
54        // AA with stroke style
55        SkPaint p;
56        p.setAntiAlias(true);
57        p.setStyle(SkPaint::kStroke_Style);
58        p.setStrokeWidth(SkIntToScalar(5));
59        fPaints.push_back(p);
60        }
61
62        {
63        // AA with stroke style, width = 0
64        SkPaint p;
65        p.setAntiAlias(true);
66        p.setStyle(SkPaint::kStroke_Style);
67        fPaints.push_back(p);
68        }
69
70        {
71        // AA with stroke and fill style
72        SkPaint p;
73        p.setAntiAlias(true);
74        p.setStyle(SkPaint::kStrokeAndFill_Style);
75        p.setStrokeWidth(SkIntToScalar(3));
76        fPaints.push_back(p);
77        }
78    }
79
80    void makeMatrices() {
81        {
82        SkMatrix m;
83        m.setIdentity();
84        fMatrices.push_back(m);
85        }
86
87        {
88        SkMatrix m;
89        m.setScale(SkIntToScalar(3), SkIntToScalar(2));
90        fMatrices.push_back(m);
91        }
92
93        {
94        SkMatrix m;
95        m.setScale(SkIntToScalar(2), SkIntToScalar(2));
96        fMatrices.push_back(m);
97        }
98
99        {
100        SkMatrix m;
101        m.setScale(SkIntToScalar(1), SkIntToScalar(2));
102        fMatrices.push_back(m);
103        }
104
105        {
106        SkMatrix m;
107        m.setScale(SkIntToScalar(4), SkIntToScalar(1));
108        fMatrices.push_back(m);
109        }
110
111        {
112        SkMatrix m;
113        m.setRotate(SkIntToScalar(90));
114        fMatrices.push_back(m);
115        }
116
117        {
118        SkMatrix m;
119        m.setSkew(SkIntToScalar(2), SkIntToScalar(3));
120        fMatrices.push_back(m);
121        }
122
123        {
124        SkMatrix m;
125        m.setRotate(SkIntToScalar(60));
126        fMatrices.push_back(m);
127        }
128    }
129
130    SkColor genColor(SkRandom* rand) {
131        SkScalar hsv[3];
132        hsv[0] = rand->nextRangeF(0.0f, 360.0f);
133        hsv[1] = rand->nextRangeF(0.75f, 1.0f);
134        hsv[2] = rand->nextRangeF(0.75f, 1.0f);
135
136        return SkHSVToColor(hsv);
137    }
138
139    void onDraw(SkCanvas* canvas) override {
140        SkRandom rand(1);
141        canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
142        SkRect rect = SkRect::MakeLTRB(-20, -30, 20, 30);
143        SkRRect circleRect;
144        circleRect.setRectXY(rect, 5, 5);
145
146        const SkScalar kXStart = 60.0f;
147        const SkScalar kYStart = 80.0f;
148        const int kXStep = 150;
149        const int kYStep = 160;
150        int maxX = fMatrices.count();
151
152        SkPaint rectPaint;
153        rectPaint.setAntiAlias(true);
154        rectPaint.setStyle(SkPaint::kStroke_Style);
155        rectPaint.setStrokeWidth(SkIntToScalar(0));
156        rectPaint.setColor(SK_ColorLTGRAY);
157
158        int testCount = 0;
159        for (int i = 0; i < fPaints.count(); ++i) {
160            for (int j = 0; j < fMatrices.count(); ++j) {
161                canvas->save();
162                SkMatrix mat = fMatrices[j];
163                // position the roundrect, and make it at off-integer coords.
164                mat.postTranslate(kXStart + SK_Scalar1 * kXStep * (testCount % maxX) +
165                                  SK_Scalar1 / 4,
166                                  kYStart + SK_Scalar1 * kYStep * (testCount / maxX) +
167                                  3 * SK_Scalar1 / 4);
168                canvas->concat(mat);
169
170                SkColor color = genColor(&rand);
171                fPaints[i].setColor(color);
172
173                canvas->drawRect(rect, rectPaint);
174                canvas->drawRRect(circleRect, fPaints[i]);
175
176                canvas->restore();
177
178                ++testCount;
179            }
180        }
181
182        // special cases
183
184        // non-scaled tall and skinny roundrect
185        for (int i = 0; i < fPaints.count(); ++i) {
186            SkRect rect = SkRect::MakeLTRB(-20, -60, 20, 60);
187            SkRRect ellipseRect;
188            ellipseRect.setRectXY(rect, 5, 10);
189
190            canvas->save();
191            // position the roundrect, and make it at off-integer coords.
192            canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.55f + SK_Scalar1 / 4,
193                              kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4);
194
195            SkColor color = genColor(&rand);
196            fPaints[i].setColor(color);
197
198            canvas->drawRect(rect, rectPaint);
199            canvas->drawRRect(ellipseRect, fPaints[i]);
200            canvas->restore();
201        }
202
203        // non-scaled wide and short roundrect
204        for (int i = 0; i < fPaints.count(); ++i) {
205            SkRect rect = SkRect::MakeLTRB(-80, -30, 80, 30);
206            SkRRect ellipseRect;
207            ellipseRect.setRectXY(rect, 20, 5);
208
209            canvas->save();
210            // position the roundrect, and make it at off-integer coords.
211            canvas->translate(kXStart + SK_Scalar1 * kXStep * 4 + SK_Scalar1 / 4,
212                              kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
213                              SK_ScalarHalf * kYStep);
214
215            SkColor color = genColor(&rand);
216            fPaints[i].setColor(color);
217
218            canvas->drawRect(rect, rectPaint);
219            canvas->drawRRect(ellipseRect, fPaints[i]);
220            canvas->restore();
221        }
222
223        // super skinny roundrect
224        for (int i = 0; i < fPaints.count(); ++i) {
225            SkRect rect = SkRect::MakeLTRB(0, -60, 1, 60);
226            SkRRect circleRect;
227            circleRect.setRectXY(rect, 5, 5);
228
229            canvas->save();
230            // position the roundrect, and make it at off-integer coords.
231            canvas->translate(kXStart + SK_Scalar1 * kXStep * 3.25f + SK_Scalar1 / 4,
232                              kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4);
233
234            SkColor color = genColor(&rand);
235            fPaints[i].setColor(color);
236
237            canvas->drawRRect(circleRect, fPaints[i]);
238            canvas->restore();
239        }
240
241        // super short roundrect
242        for (int i = 0; i < fPaints.count(); ++i) {
243            SkRect rect = SkRect::MakeLTRB(-80, -1, 80, 0);
244            SkRRect circleRect;
245            circleRect.setRectXY(rect, 5, 5);
246
247            canvas->save();
248            // position the roundrect, and make it at off-integer coords.
249            canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.5f + SK_Scalar1 / 4,
250                              kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
251                              SK_ScalarHalf * kYStep);
252
253            SkColor color = genColor(&rand);
254            fPaints[i].setColor(color);
255
256            canvas->drawRRect(circleRect, fPaints[i]);
257            canvas->restore();
258        }
259
260        // radial gradient
261        SkPoint center = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
262        SkColor colors[] = { SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN };
263        SkScalar pos[] = { 0, SK_ScalarHalf, SK_Scalar1 };
264        SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center,
265                                                     SkIntToScalar(20),
266                                                     colors,
267                                                     pos,
268                                                     SK_ARRAY_COUNT(colors),
269                                                     SkShader::kClamp_TileMode));
270
271        for (int i = 0; i < fPaints.count(); ++i) {
272            canvas->save();
273            // position the path, and make it at off-integer coords.
274            canvas->translate(kXStart + SK_Scalar1 * kXStep * 0 + SK_Scalar1 / 4,
275                              kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
276                              SK_ScalarHalf * kYStep);
277
278            SkColor color = genColor(&rand);
279            fPaints[i].setColor(color);
280            fPaints[i].setShader(shader);
281
282            canvas->drawRect(rect, rectPaint);
283            canvas->drawRRect(circleRect, fPaints[i]);
284
285            fPaints[i].setShader(NULL);
286
287            canvas->restore();
288        }
289
290        // strokes and radii
291        {
292            SkScalar radii[][2] = {
293                {10,10},
294                {5,15},
295                {5,15},
296                {5,15}
297            };
298
299            SkScalar strokeWidths[] = {
300                20, 10, 20, 40
301            };
302
303            for (int i = 0; i < 4; ++i) {
304                SkRRect circleRect;
305                circleRect.setRectXY(rect, radii[i][0], radii[i][1]);
306
307                canvas->save();
308                // position the roundrect, and make it at off-integer coords.
309                canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4,
310                                  kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
311                                  SK_ScalarHalf * kYStep);
312
313                SkColor color = genColor(&rand);
314
315                SkPaint p;
316                p.setAntiAlias(true);
317                p.setStyle(SkPaint::kStroke_Style);
318                p.setStrokeWidth(strokeWidths[i]);
319                p.setColor(color);
320
321                canvas->drawRRect(circleRect, p);
322                canvas->restore();
323            }
324        }
325
326    }
327
328private:
329    SkTArray<SkPaint> fPaints;
330    SkTArray<SkMatrix> fMatrices;
331
332    typedef GM INHERITED;
333};
334
335//////////////////////////////////////////////////////////////////////////////
336
337static GM* MyFactory(void*) { return new RoundRectGM; }
338static GMRegistry reg(MyFactory);
339
340}
341