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
21static SkColor gen_color(SkRandom* rand) {
22    SkScalar hsv[3];
23    hsv[0] = rand->nextRangeF(0.0f, 360.0f);
24    hsv[1] = rand->nextRangeF(0.75f, 1.0f);
25    hsv[2] = rand->nextRangeF(0.75f, 1.0f);
26
27    return sk_tool_utils::color_to_565(SkHSVToColor(hsv));
28}
29
30class RoundRectGM : public GM {
31public:
32    RoundRectGM() {
33        this->setBGColor(0xFF000000);
34        this->makePaints();
35        this->makeMatrices();
36    }
37
38protected:
39
40    SkString onShortName() override {
41        return SkString("roundrects");
42    }
43
44    SkISize onISize() override {
45        return SkISize::Make(1200, 900);
46    }
47
48    void makePaints() {
49        {
50        // no AA
51        SkPaint p;
52        fPaints.push_back(p);
53        }
54
55        {
56        // AA
57        SkPaint p;
58        p.setAntiAlias(true);
59        fPaints.push_back(p);
60        }
61
62        {
63        // AA with stroke style
64        SkPaint p;
65        p.setAntiAlias(true);
66        p.setStyle(SkPaint::kStroke_Style);
67        p.setStrokeWidth(SkIntToScalar(5));
68        fPaints.push_back(p);
69        }
70
71        {
72        // AA with stroke style, width = 0
73        SkPaint p;
74        p.setAntiAlias(true);
75        p.setStyle(SkPaint::kStroke_Style);
76        fPaints.push_back(p);
77        }
78
79        {
80        // AA with stroke and fill style
81        SkPaint p;
82        p.setAntiAlias(true);
83        p.setStyle(SkPaint::kStrokeAndFill_Style);
84        p.setStrokeWidth(SkIntToScalar(3));
85        fPaints.push_back(p);
86        }
87    }
88
89    void makeMatrices() {
90        {
91        SkMatrix m;
92        m.setIdentity();
93        fMatrices.push_back(m);
94        }
95
96        {
97        SkMatrix m;
98        m.setScale(SkIntToScalar(3), SkIntToScalar(2));
99        fMatrices.push_back(m);
100        }
101
102        {
103        SkMatrix m;
104        m.setScale(SkIntToScalar(2), SkIntToScalar(2));
105        fMatrices.push_back(m);
106        }
107
108        {
109        SkMatrix m;
110        m.setScale(SkIntToScalar(1), SkIntToScalar(2));
111        fMatrices.push_back(m);
112        }
113
114        {
115        SkMatrix m;
116        m.setScale(SkIntToScalar(4), SkIntToScalar(1));
117        fMatrices.push_back(m);
118        }
119
120        {
121        SkMatrix m;
122        m.setRotate(SkIntToScalar(90));
123        fMatrices.push_back(m);
124        }
125
126        {
127        SkMatrix m;
128        m.setSkew(SkIntToScalar(2), SkIntToScalar(3));
129        fMatrices.push_back(m);
130        }
131
132        {
133        SkMatrix m;
134        m.setRotate(SkIntToScalar(60));
135        fMatrices.push_back(m);
136        }
137    }
138
139    void onDraw(SkCanvas* canvas) override {
140        SkRandom rand(1);
141        canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
142        const 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_tool_utils::color_to_565(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 = gen_color(&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 = gen_color(&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 = gen_color(&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 = gen_color(&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 = gen_color(&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 = gen_color(&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(nullptr);
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 = gen_color(&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        // test old entry point ( https://bug.skia.org/3786 )
327        {
328            canvas->save();
329
330            canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4,
331                              kYStart + SK_Scalar1 * kYStep * 4 + SK_Scalar1 / 4 +
332                              SK_ScalarHalf * kYStep);
333
334            const SkColor color = gen_color(&rand);
335
336            SkPaint p;
337            p.setColor(color);
338
339            const SkRect oooRect = { 20, 30, -20, -30 };     // intentionally out of order
340            canvas->drawRoundRect(oooRect, 10, 10, p);
341
342            canvas->restore();
343        }
344    }
345
346private:
347    SkTArray<SkPaint> fPaints;
348    SkTArray<SkMatrix> fMatrices;
349
350    typedef GM INHERITED;
351};
352
353//////////////////////////////////////////////////////////////////////////////
354
355static GM* MyFactory(void*) { return new RoundRectGM; }
356static GMRegistry reg(MyFactory);
357
358}
359