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