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