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/SkPath.h" 14 #include "include/core/SkPathTypes.h" 15 #include "include/core/SkPoint.h" 16 #include "include/core/SkRect.h" 17 #include "include/core/SkScalar.h" 18 #include "include/core/SkShader.h" 19 #include "include/core/SkSize.h" 20 #include "include/core/SkString.h" 21 #include "include/core/SkTileMode.h" 22 #include "include/core/SkTypes.h" 23 #include "include/effects/SkGradientShader.h" 24 #include "include/private/base/SkTArray.h" 25 #include "src/base/SkRandom.h" 26 #include "tools/ToolUtils.h" 27 28 using namespace skia_private; 29 30 namespace skiagm { 31 32 class OvalGM : public GM { 33 public: OvalGM()34 OvalGM() { 35 this->setBGColor(0xFF000000); 36 this->makePaints(); 37 this->makeMatrices(); 38 } 39 40 protected: getName() const41 SkString getName() const override { return SkString("ovals"); } 42 getISize()43 SkISize getISize() override { return SkISize::Make(1200, 900); } 44 makePaints()45 void makePaints() { 46 { 47 // no AA 48 SkPaint p; 49 fPaints.push_back(p); 50 } 51 52 { 53 // AA 54 SkPaint p; 55 p.setAntiAlias(true); 56 fPaints.push_back(p); 57 } 58 59 { 60 // AA with stroke style 61 SkPaint p; 62 p.setAntiAlias(true); 63 p.setStyle(SkPaint::kStroke_Style); 64 p.setStrokeWidth(SkIntToScalar(5)); 65 fPaints.push_back(p); 66 } 67 68 { 69 // AA with stroke style, width = 0 70 SkPaint p; 71 p.setAntiAlias(true); 72 p.setStyle(SkPaint::kStroke_Style); 73 fPaints.push_back(p); 74 } 75 76 { 77 // AA with stroke and fill style 78 SkPaint p; 79 p.setAntiAlias(true); 80 p.setStyle(SkPaint::kStrokeAndFill_Style); 81 p.setStrokeWidth(SkIntToScalar(3)); 82 fPaints.push_back(p); 83 } 84 } 85 makeMatrices()86 void makeMatrices() { 87 { 88 SkMatrix m; 89 m.setIdentity(); 90 fMatrices.push_back(m); 91 } 92 93 { 94 SkMatrix m; 95 m.setScale(SkIntToScalar(3), SkIntToScalar(2)); 96 fMatrices.push_back(m); 97 } 98 99 { 100 SkMatrix m; 101 m.setScale(SkIntToScalar(2), SkIntToScalar(2)); 102 fMatrices.push_back(m); 103 } 104 105 { 106 SkMatrix m; 107 m.setScale(SkIntToScalar(1), SkIntToScalar(2)); 108 fMatrices.push_back(m); 109 } 110 111 { 112 SkMatrix m; 113 m.setScale(SkIntToScalar(4), SkIntToScalar(1)); 114 fMatrices.push_back(m); 115 } 116 117 { 118 SkMatrix m; 119 m.setRotate(SkIntToScalar(90)); 120 fMatrices.push_back(m); 121 } 122 123 { 124 SkMatrix m; 125 m.setSkew(SkIntToScalar(2), SkIntToScalar(3)); 126 fMatrices.push_back(m); 127 } 128 129 { 130 SkMatrix m; 131 m.setRotate(SkIntToScalar(60)); 132 fMatrices.push_back(m); 133 } 134 } 135 genColor(SkRandom * rand)136 SkColor genColor(SkRandom* rand) { 137 SkScalar hsv[3]; 138 hsv[0] = rand->nextRangeF(0.0f, 360.0f); 139 hsv[1] = rand->nextRangeF(0.75f, 1.0f); 140 hsv[2] = rand->nextRangeF(0.75f, 1.0f); 141 142 return ToolUtils::color_to_565(SkHSVToColor(hsv)); 143 } 144 onDraw(SkCanvas * canvas)145 void onDraw(SkCanvas* canvas) override { 146 SkRandom rand(1); 147 canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1); 148 const SkRect kOval = SkRect::MakeLTRB(-20, -30, 20, 30); 149 150 const SkScalar kXStart = 60.0f; 151 const SkScalar kYStart = 80.0f; 152 const int kXStep = 150; 153 const int kYStep = 160; 154 int maxX = fMatrices.size(); 155 156 SkPaint rectPaint; 157 rectPaint.setAntiAlias(true); 158 rectPaint.setStyle(SkPaint::kStroke_Style); 159 rectPaint.setStrokeWidth(SkIntToScalar(0)); 160 rectPaint.setColor(SK_ColorLTGRAY); 161 162 int testCount = 0; 163 for (int i = 0; i < fPaints.size(); ++i) { 164 for (int j = 0; j < fMatrices.size(); ++j) { 165 canvas->save(); 166 SkMatrix mat = fMatrices[j]; 167 // position the oval, and make it at off-integer coords. 168 mat.postTranslate(kXStart + SK_Scalar1 * kXStep * (testCount % maxX) + 169 SK_Scalar1 / 4, 170 kYStart + SK_Scalar1 * kYStep * (testCount / maxX) + 171 3 * SK_Scalar1 / 4); 172 canvas->concat(mat); 173 174 SkColor color = genColor(&rand); 175 fPaints[i].setColor(color); 176 177 canvas->drawRect(kOval, rectPaint); 178 canvas->drawOval(kOval, fPaints[i]); 179 180 canvas->restore(); 181 182 ++testCount; 183 } 184 } 185 186 // special cases 187 188 // non-scaled tall and skinny oval 189 for (int i = 0; i < fPaints.size(); ++i) { 190 SkRect oval = SkRect::MakeLTRB(-20, -60, 20, 60); 191 canvas->save(); 192 // position the oval, 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 = genColor(&rand); 197 fPaints[i].setColor(color); 198 199 canvas->drawRect(oval, rectPaint); 200 canvas->drawOval(oval, fPaints[i]); 201 canvas->restore(); 202 } 203 204 // non-scaled wide and short oval 205 for (int i = 0; i < fPaints.size(); ++i) { 206 SkRect oval = SkRect::MakeLTRB(-80, -30, 80, 30); 207 canvas->save(); 208 // position the oval, and make it at off-integer coords. 209 canvas->translate(kXStart + SK_Scalar1 * kXStep * 4 + SK_Scalar1 / 4, 210 kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + 211 SK_ScalarHalf * kYStep); 212 213 SkColor color = genColor(&rand); 214 fPaints[i].setColor(color); 215 216 canvas->drawRect(oval, rectPaint); 217 canvas->drawOval(oval, fPaints[i]); 218 canvas->restore(); 219 } 220 221 // super skinny oval 222 for (int i = 0; i < fPaints.size(); ++i) { 223 SkRect oval = SkRect::MakeLTRB(0, -60, 1, 60); 224 canvas->save(); 225 // position the oval, and make it at off-integer coords. 226 canvas->translate(kXStart + SK_Scalar1 * kXStep * 3.25f + SK_Scalar1 / 4, 227 kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4); 228 229 SkColor color = genColor(&rand); 230 fPaints[i].setColor(color); 231 232 canvas->drawOval(oval, fPaints[i]); 233 canvas->restore(); 234 } 235 236 // super short oval 237 for (int i = 0; i < fPaints.size(); ++i) { 238 SkRect oval = SkRect::MakeLTRB(-80, -1, 80, 0); 239 canvas->save(); 240 // position the oval, and make it at off-integer coords. 241 canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.5f + SK_Scalar1 / 4, 242 kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + 243 SK_ScalarHalf * kYStep); 244 245 SkColor color = genColor(&rand); 246 fPaints[i].setColor(color); 247 248 canvas->drawOval(oval, fPaints[i]); 249 canvas->restore(); 250 } 251 252 // radial gradient 253 SkPoint center = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0)); 254 SkColor colors[] = { SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN }; 255 SkScalar pos[] = { 0, SK_ScalarHalf, SK_Scalar1 }; 256 auto shader = SkGradientShader::MakeRadial(center, 20, colors, pos, std::size(colors), 257 SkTileMode::kClamp); 258 259 for (int i = 0; i < fPaints.size(); ++i) { 260 canvas->save(); 261 // position the path, and make it at off-integer coords. 262 canvas->translate(kXStart + SK_Scalar1 * kXStep * 0 + SK_Scalar1 / 4, 263 kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + 264 SK_ScalarHalf * kYStep); 265 266 SkColor color = genColor(&rand); 267 fPaints[i].setColor(color); 268 fPaints[i].setShader(shader); 269 270 canvas->drawRect(kOval, rectPaint); 271 canvas->drawOval(kOval, fPaints[i]); 272 273 fPaints[i].setShader(nullptr); 274 275 canvas->restore(); 276 } 277 278 // reflected oval 279 for (int i = 0; i < fPaints.size(); ++i) { 280 SkRect oval = SkRect::MakeLTRB(-30, -30, 30, 30); 281 canvas->save(); 282 // position the oval, and make it at off-integer coords. 283 canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4, 284 kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + 285 SK_ScalarHalf * kYStep); 286 canvas->rotate(90); 287 canvas->scale(1, -1); 288 canvas->scale(1, 0.66f); 289 290 SkColor color = genColor(&rand); 291 fPaints[i].setColor(color); 292 293 canvas->drawRect(oval, rectPaint); 294 canvas->drawOval(oval, fPaints[i]); 295 canvas->restore(); 296 } 297 } 298 299 private: 300 TArray<SkPaint> fPaints; 301 TArray<SkMatrix> fMatrices; 302 303 using INHERITED = GM; 304 }; 305 306 ////////////////////////////////////////////////////////////////////////////// 307 308 DEF_GM( return new OvalGM; ) 309 310 } // namespace skiagm 311 312 DEF_SIMPLE_GM(open_ovals, canvas, 225, 110) { 313 SkPaint paint; 314 paint.setAntiAlias(true); 315 paint.setStyle(SkPaint::kStroke_Style); 316 317 const SkRect rect = SkRect::MakeWH(50, 100); 318 const SkPathDirection dir = SkPathDirection::kCW; 319 const int start = 1; 320 321 // We stroke several open ovals to see how they behave 322 canvas->translate(5, 5); 323 __anonacd42a350102(const SkPath& p) 324 auto doRow = [&](const SkPath& p) { 325 canvas->drawPath(p, paint); 326 canvas->translate(55, 0); 327 }; 328 329 // Default case (left open) looks like an oval 330 SkPath path; 331 path.addOpenOval(rect, dir, start); 332 doRow(path); 333 334 // Closing makes us technically be an oval, but should look the same 335 path.close(); 336 doRow(path); 337 338 // Moving before the oval adds a line to the start 339 path.reset(); 340 path.moveTo(rect.center()); 341 path.addOpenOval(rect, dir, start); 342 doRow(path); 343 344 // Similarly, lineTo after the oval starts from the start/end point 345 path.reset(); 346 path.addOpenOval(rect, dir, start); 347 path.lineTo(rect.center()); 348 doRow(path); 349 } 350