1 /* 2 * Copyright 2011 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 "SkCanvas.h" 11 #include "SkPaint.h" 12 #include "SkPath.h" 13 #include "SkRandom.h" 14 15 // https://bug.skia.org/1316 shows that this cubic, when slightly clipped, creates big 16 // (incorrect) changes to its control points. 17 class ClippedCubicGM : public skiagm::GM { 18 public: ClippedCubicGM()19 ClippedCubicGM() {} 20 21 protected: 22 onShortName()23 SkString onShortName() { 24 return SkString("clippedcubic"); 25 } 26 onISize()27 SkISize onISize() { return SkISize::Make(1240, 390); } 28 onDraw(SkCanvas * canvas)29 virtual void onDraw(SkCanvas* canvas) { 30 SkPath path; 31 path.moveTo(0, 0); 32 path.cubicTo(140, 150, 40, 10, 170, 150); 33 34 SkPaint paint; 35 SkRect bounds = path.getBounds(); 36 37 for (SkScalar dy = -1; dy <= 1; dy += 1) { 38 canvas->save(); 39 for (SkScalar dx = -1; dx <= 1; dx += 1) { 40 canvas->save(); 41 canvas->clipRect(bounds); 42 canvas->translate(dx, dy); 43 canvas->drawPath(path, paint); 44 canvas->restore(); 45 46 canvas->translate(bounds.width(), 0); 47 } 48 canvas->restore(); 49 canvas->translate(0, bounds.height()); 50 } 51 } 52 53 private: 54 typedef skiagm::GM INHERITED; 55 }; 56 57 58 class ClippedCubic2GM : public skiagm::GM { 59 public: ClippedCubic2GM()60 ClippedCubic2GM() {} 61 62 protected: 63 onShortName()64 SkString onShortName() override { 65 return SkString("clippedcubic2"); 66 } 67 onISize()68 SkISize onISize() override { return SkISize::Make(1240, 390); } 69 onDraw(SkCanvas * canvas)70 void onDraw(SkCanvas* canvas) override { 71 canvas->save(); 72 canvas->translate(-2, 120); 73 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 150)); 74 canvas->translate(0, 170); 75 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 100)); 76 canvas->translate(0, 170); 77 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 30, 150)); 78 canvas->translate(0, 170); 79 drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 10, 150)); 80 canvas->restore(); 81 canvas->save(); 82 canvas->translate(20, -2); 83 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 80)); 84 canvas->translate(170, 0); 85 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 100, 80)); 86 canvas->translate(170, 0); 87 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 30)); 88 canvas->translate(170, 0); 89 drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 10)); 90 canvas->restore(); 91 } 92 drawOne(SkCanvas * canvas,const SkPath & path,const SkRect & clip)93 void drawOne(SkCanvas* canvas, const SkPath& path, const SkRect& clip) { 94 SkPaint framePaint, fillPaint; 95 framePaint.setStyle(SkPaint::kStroke_Style); 96 canvas->drawRect(clip, framePaint); 97 canvas->drawPath(path, framePaint); 98 canvas->save(); 99 canvas->clipRect(clip); 100 canvas->drawPath(path, fillPaint); 101 canvas->restore(); 102 } 103 onOnceBeforeDraw()104 void onOnceBeforeDraw() override { 105 fPath.moveTo(69.7030518991886f, 0); 106 fPath.cubicTo( 69.7030518991886f, 21.831149999999997f, 107 58.08369508178456f, 43.66448333333333f, 34.8449814469765f, 65.5f); 108 fPath.cubicTo( 11.608591683531916f, 87.33115f, -0.010765133872116195f, 109.16448333333332f, 109 -0.013089005235602302f, 131); 110 fPath.close(); 111 fFlipped = fPath; 112 SkMatrix matrix; 113 matrix.reset(); 114 matrix.setScaleX(0); 115 matrix.setScaleY(0); 116 matrix.setSkewX(1); 117 matrix.setSkewY(1); 118 fFlipped.transform(matrix); 119 } 120 121 SkPath fPath; 122 SkPath fFlipped; 123 private: 124 typedef skiagm::GM INHERITED; 125 }; 126 127 128 class CubicPathGM : public skiagm::GM { 129 public: CubicPathGM()130 CubicPathGM() {} 131 132 protected: 133 onShortName()134 SkString onShortName() { 135 return SkString("cubicpath"); 136 } 137 onISize()138 SkISize onISize() { return SkISize::Make(1240, 390); } 139 drawPath(SkPath & path,SkCanvas * canvas,SkColor color,const SkRect & clip,SkPaint::Cap cap,SkPaint::Join join,SkPaint::Style style,SkPath::FillType fill,SkScalar strokeWidth)140 void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, 141 const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, 142 SkPaint::Style style, SkPath::FillType fill, 143 SkScalar strokeWidth) { 144 path.setFillType(fill); 145 SkPaint paint; 146 paint.setStrokeCap(cap); 147 paint.setStrokeWidth(strokeWidth); 148 paint.setStrokeJoin(join); 149 paint.setColor(color); 150 paint.setStyle(style); 151 canvas->save(); 152 canvas->clipRect(clip); 153 canvas->drawPath(path, paint); 154 canvas->restore(); 155 } 156 onDraw(SkCanvas * canvas)157 virtual void onDraw(SkCanvas* canvas) { 158 struct FillAndName { 159 SkPath::FillType fFill; 160 const char* fName; 161 }; 162 constexpr FillAndName gFills[] = { 163 {SkPath::kWinding_FillType, "Winding"}, 164 {SkPath::kEvenOdd_FillType, "Even / Odd"}, 165 {SkPath::kInverseWinding_FillType, "Inverse Winding"}, 166 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, 167 }; 168 struct StyleAndName { 169 SkPaint::Style fStyle; 170 const char* fName; 171 }; 172 constexpr StyleAndName gStyles[] = { 173 {SkPaint::kFill_Style, "Fill"}, 174 {SkPaint::kStroke_Style, "Stroke"}, 175 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, 176 }; 177 struct CapAndName { 178 SkPaint::Cap fCap; 179 SkPaint::Join fJoin; 180 const char* fName; 181 }; 182 constexpr CapAndName gCaps[] = { 183 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, 184 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, 185 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} 186 }; 187 struct PathAndName { 188 SkPath fPath; 189 const char* fName; 190 }; 191 PathAndName path; 192 path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); 193 path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1, 194 60*SK_Scalar1, 20*SK_Scalar1, 195 75*SK_Scalar1, 10*SK_Scalar1); 196 path.fName = "moveTo-cubic"; 197 198 SkPaint titlePaint; 199 titlePaint.setColor(SK_ColorBLACK); 200 titlePaint.setAntiAlias(true); 201 SkFont font(sk_tool_utils::create_portable_typeface(), 15); 202 const char title[] = "Cubic Drawn Into Rectangle Clips With " 203 "Indicated Style, Fill and Linecaps, with stroke width 10"; 204 canvas->drawString(title, 20, 20, font, titlePaint); 205 206 SkRandom rand; 207 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); 208 canvas->save(); 209 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); 210 canvas->save(); 211 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { 212 if (0 < cap) { 213 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); 214 } 215 canvas->save(); 216 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { 217 if (0 < fill) { 218 canvas->translate(0, rect.height() + 40 * SK_Scalar1); 219 } 220 canvas->save(); 221 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { 222 if (0 < style) { 223 canvas->translate(rect.width() + 40 * SK_Scalar1, 0); 224 } 225 226 SkColor color = 0xff007000; 227 this->drawPath(path.fPath, canvas, color, rect, 228 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, 229 gFills[fill].fFill, SK_Scalar1*10); 230 231 SkPaint rectPaint; 232 rectPaint.setColor(SK_ColorBLACK); 233 rectPaint.setStyle(SkPaint::kStroke_Style); 234 rectPaint.setStrokeWidth(-1); 235 rectPaint.setAntiAlias(true); 236 canvas->drawRect(rect, rectPaint); 237 238 SkPaint labelPaint; 239 labelPaint.setColor(color); 240 font.setSize(10); 241 canvas->drawString(gStyles[style].fName, 0, rect.height() + 12, font, labelPaint); 242 canvas->drawString(gFills[fill].fName, 0, rect.height() + 24, font, labelPaint); 243 canvas->drawString(gCaps[cap].fName, 0, rect.height() + 36, font, labelPaint); 244 } 245 canvas->restore(); 246 } 247 canvas->restore(); 248 } 249 canvas->restore(); 250 canvas->restore(); 251 } 252 253 private: 254 typedef skiagm::GM INHERITED; 255 }; 256 257 class CubicClosePathGM : public skiagm::GM { 258 public: CubicClosePathGM()259 CubicClosePathGM() {} 260 261 protected: 262 onShortName()263 SkString onShortName() { 264 return SkString("cubicclosepath"); 265 } 266 onISize()267 SkISize onISize() { return SkISize::Make(1240, 390); } 268 drawPath(SkPath & path,SkCanvas * canvas,SkColor color,const SkRect & clip,SkPaint::Cap cap,SkPaint::Join join,SkPaint::Style style,SkPath::FillType fill,SkScalar strokeWidth)269 void drawPath(SkPath& path,SkCanvas* canvas,SkColor color, 270 const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join, 271 SkPaint::Style style, SkPath::FillType fill, 272 SkScalar strokeWidth) { 273 path.setFillType(fill); 274 SkPaint paint; 275 paint.setStrokeCap(cap); 276 paint.setStrokeWidth(strokeWidth); 277 paint.setStrokeJoin(join); 278 paint.setColor(color); 279 paint.setStyle(style); 280 canvas->save(); 281 canvas->clipRect(clip); 282 canvas->drawPath(path, paint); 283 canvas->restore(); 284 } 285 onDraw(SkCanvas * canvas)286 virtual void onDraw(SkCanvas* canvas) { 287 struct FillAndName { 288 SkPath::FillType fFill; 289 const char* fName; 290 }; 291 constexpr FillAndName gFills[] = { 292 {SkPath::kWinding_FillType, "Winding"}, 293 {SkPath::kEvenOdd_FillType, "Even / Odd"}, 294 {SkPath::kInverseWinding_FillType, "Inverse Winding"}, 295 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}, 296 }; 297 struct StyleAndName { 298 SkPaint::Style fStyle; 299 const char* fName; 300 }; 301 constexpr StyleAndName gStyles[] = { 302 {SkPaint::kFill_Style, "Fill"}, 303 {SkPaint::kStroke_Style, "Stroke"}, 304 {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"}, 305 }; 306 struct CapAndName { 307 SkPaint::Cap fCap; 308 SkPaint::Join fJoin; 309 const char* fName; 310 }; 311 constexpr CapAndName gCaps[] = { 312 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, 313 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, 314 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} 315 }; 316 struct PathAndName { 317 SkPath fPath; 318 const char* fName; 319 }; 320 PathAndName path; 321 path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1); 322 path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1, 323 60*SK_Scalar1, 20*SK_Scalar1, 324 75*SK_Scalar1, 10*SK_Scalar1); 325 path.fPath.close(); 326 path.fName = "moveTo-cubic-close"; 327 328 SkPaint titlePaint; 329 titlePaint.setColor(SK_ColorBLACK); 330 titlePaint.setAntiAlias(true); 331 SkFont font(sk_tool_utils::create_portable_typeface(), 15); 332 const char title[] = "Cubic Closed Drawn Into Rectangle Clips With " 333 "Indicated Style, Fill and Linecaps, with stroke width 10"; 334 canvas->drawString(title, 20, 20, font, titlePaint); 335 336 SkRandom rand; 337 SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1); 338 canvas->save(); 339 canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1); 340 canvas->save(); 341 for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) { 342 if (0 < cap) { 343 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0); 344 } 345 canvas->save(); 346 for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) { 347 if (0 < fill) { 348 canvas->translate(0, rect.height() + 40 * SK_Scalar1); 349 } 350 canvas->save(); 351 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) { 352 if (0 < style) { 353 canvas->translate(rect.width() + 40 * SK_Scalar1, 0); 354 } 355 356 SkColor color = 0xff007000; 357 this->drawPath(path.fPath, canvas, color, rect, 358 gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle, 359 gFills[fill].fFill, SK_Scalar1*10); 360 361 SkPaint rectPaint; 362 rectPaint.setColor(SK_ColorBLACK); 363 rectPaint.setStyle(SkPaint::kStroke_Style); 364 rectPaint.setStrokeWidth(-1); 365 rectPaint.setAntiAlias(true); 366 canvas->drawRect(rect, rectPaint); 367 368 SkPaint labelPaint; 369 labelPaint.setColor(color); 370 labelPaint.setAntiAlias(true); 371 font.setSize(10); 372 canvas->drawString(gStyles[style].fName, 0, rect.height() + 12, font, labelPaint); 373 canvas->drawString(gFills[fill].fName, 0, rect.height() + 24, font, labelPaint); 374 canvas->drawString(gCaps[cap].fName, 0, rect.height() + 36, font, labelPaint); 375 } 376 canvas->restore(); 377 } 378 canvas->restore(); 379 } 380 canvas->restore(); 381 canvas->restore(); 382 } 383 384 private: 385 typedef skiagm::GM INHERITED; 386 }; 387 388 DEF_SIMPLE_GM(bug5099, canvas, 50, 50) { 389 SkPaint p; 390 p.setColor(SK_ColorRED); 391 p.setAntiAlias(true); 392 p.setStyle(SkPaint::kStroke_Style); 393 p.setStrokeWidth(10); 394 395 SkPath path; 396 path.moveTo(6, 27); 397 path.cubicTo(31.5f, 1.5f, 3.5f, 4.5f, 29, 29); 398 canvas->drawPath(path, p); 399 } 400 401 DEF_SIMPLE_GM(bug6083, canvas, 100, 50) { 402 SkPaint p; 403 p.setColor(SK_ColorRED); 404 p.setAntiAlias(true); 405 p.setStyle(SkPaint::kStroke_Style); 406 p.setStrokeWidth(15); 407 canvas->translate(-500, -130); 408 SkPath path; 409 path.moveTo(500.988f, 155.200f); 410 path.lineTo(526.109f, 155.200f); 411 SkPoint p1 = { 526.109f, 155.200f }; 412 SkPoint p2 = { 525.968f, 212.968f }; 413 SkPoint p3 = { 526.109f, 241.840f }; 414 path.cubicTo(p1, p2, p3); 415 canvas->drawPath(path, p); 416 canvas->translate(50, 0); 417 path.reset(); 418 p2.set(525.968f, 213.172f); 419 path.moveTo(500.988f, 155.200f); 420 path.lineTo(526.109f, 155.200f); 421 path.cubicTo(p1, p2, p3); 422 canvas->drawPath(path, p); 423 } 424 425 ////////////////////////////////////////////////////////////////////////////// 426 427 DEF_GM( return new CubicPathGM; ) 428 DEF_GM( return new CubicClosePathGM; ) 429 DEF_GM( return new ClippedCubicGM; ) 430 DEF_GM( return new ClippedCubic2GM; ) 431