xref: /aosp_15_r20/external/skia/gm/roundrects.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2013 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/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColor.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPoint.h"
14 #include "include/core/SkRRect.h"
15 #include "include/core/SkRect.h"
16 #include "include/core/SkScalar.h"
17 #include "include/core/SkShader.h"
18 #include "include/core/SkSize.h"
19 #include "include/core/SkString.h"
20 #include "include/core/SkTileMode.h"
21 #include "include/core/SkTypes.h"
22 #include "include/effects/SkGradientShader.h"
23 #include "include/private/base/SkTArray.h"
24 #include "src/base/SkRandom.h"
25 #include "tools/ToolUtils.h"
26 
27 using namespace skia_private;
28 
29 namespace skiagm {
30 
gen_color(SkRandom * rand)31 static SkColor gen_color(SkRandom* rand) {
32     SkScalar hsv[3];
33     hsv[0] = rand->nextRangeF(0.0f, 360.0f);
34     hsv[1] = rand->nextRangeF(0.75f, 1.0f);
35     hsv[2] = rand->nextRangeF(0.75f, 1.0f);
36 
37     return ToolUtils::color_to_565(SkHSVToColor(hsv));
38 }
39 
40 class RoundRectGM : public GM {
41 public:
RoundRectGM()42     RoundRectGM() {
43         this->setBGColor(0xFF000000);
44         this->makePaints();
45         this->makeMatrices();
46     }
47 
48 protected:
getName() const49     SkString getName() const override { return SkString("roundrects"); }
50 
getISize()51     SkISize getISize() override { return SkISize::Make(1200, 900); }
52 
makePaints()53     void makePaints() {
54         {
55             // no AA
56             SkPaint p;
57             fPaints.push_back(p);
58         }
59 
60         {
61             // AA
62             SkPaint p;
63             p.setAntiAlias(true);
64             fPaints.push_back(p);
65         }
66 
67         {
68             // AA with stroke style
69             SkPaint p;
70             p.setAntiAlias(true);
71             p.setStyle(SkPaint::kStroke_Style);
72             p.setStrokeWidth(SkIntToScalar(5));
73             fPaints.push_back(p);
74         }
75 
76         {
77             // AA with stroke style, width = 0
78             SkPaint p;
79             p.setAntiAlias(true);
80             p.setStyle(SkPaint::kStroke_Style);
81             fPaints.push_back(p);
82         }
83 
84         {
85             // AA with stroke and fill style
86             SkPaint p;
87             p.setAntiAlias(true);
88             p.setStyle(SkPaint::kStrokeAndFill_Style);
89             p.setStrokeWidth(SkIntToScalar(3));
90             fPaints.push_back(p);
91         }
92     }
93 
makeMatrices()94     void makeMatrices() {
95         {
96             SkMatrix m;
97             m.setIdentity();
98             fMatrices.push_back(m);
99         }
100 
101         {
102             SkMatrix m;
103             m.setScale(SkIntToScalar(3), SkIntToScalar(2));
104             fMatrices.push_back(m);
105         }
106 
107         {
108             SkMatrix m;
109             m.setScale(SkIntToScalar(2), SkIntToScalar(2));
110             fMatrices.push_back(m);
111         }
112 
113         {
114             SkMatrix m;
115             m.setScale(SkIntToScalar(1), SkIntToScalar(2));
116             fMatrices.push_back(m);
117         }
118 
119         {
120             SkMatrix m;
121             m.setScale(SkIntToScalar(4), SkIntToScalar(1));
122             fMatrices.push_back(m);
123         }
124 
125         {
126             SkMatrix m;
127             m.setRotate(SkIntToScalar(90));
128             fMatrices.push_back(m);
129         }
130 
131         {
132             SkMatrix m;
133             m.setSkew(SkIntToScalar(2), SkIntToScalar(3));
134             fMatrices.push_back(m);
135         }
136 
137         {
138             SkMatrix m;
139             m.setRotate(SkIntToScalar(60));
140             fMatrices.push_back(m);
141         }
142     }
143 
onDraw(SkCanvas * canvas)144     void onDraw(SkCanvas* canvas) override {
145         SkRandom rand(1);
146         canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
147         const SkRect kRect = SkRect::MakeLTRB(-20, -30, 20, 30);
148         SkRRect circleRRect;
149         circleRRect.setRectXY(kRect, 5, 5);
150 
151         const SkScalar kXStart = 60.0f;
152         const SkScalar kYStart = 80.0f;
153         const int kXStep = 150;
154         const int kYStep = 160;
155         int maxX = fMatrices.size();
156 
157         SkPaint rectPaint;
158         rectPaint.setAntiAlias(true);
159         rectPaint.setStyle(SkPaint::kStroke_Style);
160         rectPaint.setStrokeWidth(SkIntToScalar(0));
161         rectPaint.setColor(SK_ColorLTGRAY);
162 
163         int testCount = 0;
164         for (int i = 0; i < fPaints.size(); ++i) {
165             for (int j = 0; j < fMatrices.size(); ++j) {
166                 canvas->save();
167                 SkMatrix mat = fMatrices[j];
168                 // position the roundrect, and make it at off-integer coords.
169                 mat.postTranslate(kXStart + SK_Scalar1 * kXStep * (testCount % maxX) +
170                                   SK_Scalar1 / 4,
171                                   kYStart + SK_Scalar1 * kYStep * (testCount / maxX) +
172                                   3 * SK_Scalar1 / 4);
173                 canvas->concat(mat);
174 
175                 SkColor color = gen_color(&rand);
176                 fPaints[i].setColor(color);
177 
178                 canvas->drawRect(kRect, rectPaint);
179                 canvas->drawRRect(circleRRect, fPaints[i]);
180 
181                 canvas->restore();
182 
183                 ++testCount;
184             }
185         }
186 
187         // special cases
188 
189         // non-scaled tall and skinny roundrect
190         for (int i = 0; i < fPaints.size(); ++i) {
191             SkRect rect = SkRect::MakeLTRB(-20, -60, 20, 60);
192             SkRRect ellipseRect;
193             ellipseRect.setRectXY(rect, 5, 10);
194 
195             canvas->save();
196             // position the roundrect, and make it at off-integer coords.
197             canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.55f + SK_Scalar1 / 4,
198                               kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4);
199 
200             SkColor color = gen_color(&rand);
201             fPaints[i].setColor(color);
202 
203             canvas->drawRect(rect, rectPaint);
204             canvas->drawRRect(ellipseRect, fPaints[i]);
205             canvas->restore();
206         }
207 
208         // non-scaled wide and short roundrect
209         for (int i = 0; i < fPaints.size(); ++i) {
210             SkRect rect = SkRect::MakeLTRB(-80, -30, 80, 30);
211             SkRRect ellipseRect;
212             ellipseRect.setRectXY(rect, 20, 5);
213 
214             canvas->save();
215             // position the roundrect, and make it at off-integer coords.
216             canvas->translate(kXStart + SK_Scalar1 * kXStep * 4 + SK_Scalar1 / 4,
217                               kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
218                               SK_ScalarHalf * kYStep);
219 
220             SkColor color = gen_color(&rand);
221             fPaints[i].setColor(color);
222 
223             canvas->drawRect(rect, rectPaint);
224             canvas->drawRRect(ellipseRect, fPaints[i]);
225             canvas->restore();
226         }
227 
228         // super skinny roundrect
229         for (int i = 0; i < fPaints.size(); ++i) {
230             SkRect rect = SkRect::MakeLTRB(0, -60, 1, 60);
231             SkRRect circleRect;
232             circleRect.setRectXY(rect, 5, 5);
233 
234             canvas->save();
235             // position the roundrect, and make it at off-integer coords.
236             canvas->translate(kXStart + SK_Scalar1 * kXStep * 3.25f + SK_Scalar1 / 4,
237                               kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4);
238 
239             SkColor color = gen_color(&rand);
240             fPaints[i].setColor(color);
241 
242             canvas->drawRRect(circleRect, fPaints[i]);
243             canvas->restore();
244         }
245 
246         // super short roundrect
247         for (int i = 0; i < fPaints.size(); ++i) {
248             SkRect rect = SkRect::MakeLTRB(-80, -1, 80, 0);
249             SkRRect circleRect;
250             circleRect.setRectXY(rect, 5, 5);
251 
252             canvas->save();
253             // position the roundrect, and make it at off-integer coords.
254             canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.5f + SK_Scalar1 / 4,
255                               kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
256                               SK_ScalarHalf * kYStep);
257 
258             SkColor color = gen_color(&rand);
259             fPaints[i].setColor(color);
260 
261             canvas->drawRRect(circleRect, fPaints[i]);
262             canvas->restore();
263         }
264 
265         // radial gradient
266         SkPoint center = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0));
267         SkColor colors[] = { SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN };
268         SkScalar pos[] = { 0, SK_ScalarHalf, SK_Scalar1 };
269         auto shader = SkGradientShader::MakeRadial(center, 20, colors, pos, std::size(colors),
270                                                    SkTileMode::kClamp);
271 
272         for (int i = 0; i < fPaints.size(); ++i) {
273             canvas->save();
274             // position the path, and make it at off-integer coords.
275             canvas->translate(kXStart + SK_Scalar1 * kXStep * 0 + SK_Scalar1 / 4,
276                               kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
277                               SK_ScalarHalf * kYStep);
278 
279             SkColor color = gen_color(&rand);
280             fPaints[i].setColor(color);
281             fPaints[i].setShader(shader);
282 
283             canvas->drawRect(kRect, rectPaint);
284             canvas->drawRRect(circleRRect, fPaints[i]);
285 
286             fPaints[i].setShader(nullptr);
287 
288             canvas->restore();
289         }
290 
291         // strokes and radii
292         {
293             SkScalar radii[][2] = {
294                 {10,10},
295                 {5,15},
296                 {5,15},
297                 {5,15}
298             };
299 
300             SkScalar strokeWidths[] = {
301                 20, 10, 20, 40
302             };
303 
304             for (int i = 0; i < 4; ++i) {
305                 SkRRect circleRect;
306                 circleRect.setRectXY(kRect, radii[i][0], radii[i][1]);
307 
308                 canvas->save();
309                 // position the roundrect, and make it at off-integer coords.
310                 canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4,
311                                   kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 +
312                                   SK_ScalarHalf * kYStep);
313 
314                 SkColor color = gen_color(&rand);
315 
316                 SkPaint p;
317                 p.setAntiAlias(true);
318                 p.setStyle(SkPaint::kStroke_Style);
319                 p.setStrokeWidth(strokeWidths[i]);
320                 p.setColor(color);
321 
322                 canvas->drawRRect(circleRect, p);
323                 canvas->restore();
324             }
325         }
326 
327         // test old entry point ( https://bug.skia.org/3786 )
328         {
329             canvas->save();
330 
331             canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4,
332                               kYStart + SK_Scalar1 * kYStep * 4 + SK_Scalar1 / 4 +
333                               SK_ScalarHalf * kYStep);
334 
335             const SkColor color = gen_color(&rand);
336 
337             SkPaint p;
338             p.setColor(color);
339 
340             const SkRect oooRect = { 20, 30, -20, -30 };     // intentionally out of order
341             canvas->drawRoundRect(oooRect, 10, 10, p);
342 
343             canvas->restore();
344         }
345 
346         // rrect with stroke > radius/2
347         {
348             SkRect smallRect = { -30, -20, 30, 20 };
349             SkRRect circleRect;
350             circleRect.setRectXY(smallRect, 5, 5);
351 
352             canvas->save();
353             // position the roundrect, and make it at off-integer coords.
354             canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4,
355                               kYStart - SK_Scalar1 * kYStep + 73 * SK_Scalar1 / 4 +
356                               SK_ScalarHalf * kYStep);
357 
358             SkColor color = gen_color(&rand);
359 
360             SkPaint p;
361             p.setAntiAlias(true);
362             p.setStyle(SkPaint::kStroke_Style);
363             p.setStrokeWidth(25);
364             p.setColor(color);
365 
366             canvas->drawRRect(circleRect, p);
367             canvas->restore();
368         }
369     }
370 
371 private:
372     TArray<SkPaint> fPaints;
373     TArray<SkMatrix> fMatrices;
374 
375     using INHERITED = GM;
376 };
377 
378 //////////////////////////////////////////////////////////////////////////////
379 
380 DEF_GM( return new RoundRectGM; )
381 
382 }  // namespace skiagm
383