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 19 namespace skiagm { 20 21 static 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 30 class RoundRectGM : public GM { 31 public: 32 RoundRectGM() { 33 this->setBGColor(0xFF000000); 34 this->makePaints(); 35 this->makeMatrices(); 36 } 37 38 protected: 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 346 private: 347 SkTArray<SkPaint> fPaints; 348 SkTArray<SkMatrix> fMatrices; 349 350 typedef GM INHERITED; 351 }; 352 353 ////////////////////////////////////////////////////////////////////////////// 354 355 static GM* MyFactory(void*) { return new RoundRectGM; } 356 static GMRegistry reg(MyFactory); 357 358 } 359