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