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/gm.h" 9 #include "include/core/SkCanvas.h" 10 #include "include/core/SkColor.h" 11 #include "include/core/SkFont.h" 12 #include "include/core/SkPaint.h" 13 #include "include/core/SkPathBuilder.h" 14 #include "include/core/SkPoint.h" 15 #include "include/core/SkRect.h" 16 #include "include/core/SkScalar.h" 17 #include "include/core/SkSize.h" 18 #include "include/core/SkString.h" 19 #include "include/core/SkTypeface.h" 20 #include "include/core/SkTypes.h" 21 #include "src/base/SkRandom.h" 22 #include "tools/ToolUtils.h" 23 24 namespace skiagm { 25 26 class DegenerateSegmentsGM : public GM { 27 struct PathAndName { 28 SkPath fPath; 29 const char* fName1; 30 const char* fName2; 31 }; 32 onShortName()33 SkString onShortName() override { return SkString("degeneratesegments"); } 34 onISize()35 SkISize onISize() override { return {896, 930}; } 36 37 typedef SkPoint (*AddSegmentFunc)(SkPathBuilder&, SkPoint&); 38 39 // We need to use explicit commands here, instead of addPath, because we 40 // do not want the moveTo that is added at the beginning of a path to 41 // appear in the appended path. AddMove(SkPathBuilder & path,SkPoint & startPt)42 static SkPoint AddMove(SkPathBuilder& path, SkPoint& startPt) { 43 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 44 path.moveTo(moveToPt); 45 return moveToPt; 46 } 47 AddMoveClose(SkPathBuilder & path,SkPoint & startPt)48 static SkPoint AddMoveClose(SkPathBuilder& path, SkPoint& startPt) { 49 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 50 path.moveTo(moveToPt); 51 path.close(); 52 return moveToPt; 53 } 54 AddDegenLine(SkPathBuilder & path,SkPoint & startPt)55 static SkPoint AddDegenLine(SkPathBuilder& path, SkPoint& startPt) { 56 path.lineTo(startPt); 57 return startPt; 58 } 59 AddMoveDegenLine(SkPathBuilder & path,SkPoint & startPt)60 static SkPoint AddMoveDegenLine(SkPathBuilder& path, SkPoint& startPt) { 61 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 62 path.moveTo(moveToPt); 63 path.lineTo(moveToPt); 64 return moveToPt; 65 } 66 AddMoveDegenLineClose(SkPathBuilder & path,SkPoint & startPt)67 static SkPoint AddMoveDegenLineClose(SkPathBuilder& path, SkPoint& startPt) { 68 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 69 path.moveTo(moveToPt); 70 path.lineTo(moveToPt); 71 path.close(); 72 return moveToPt; 73 } 74 AddDegenQuad(SkPathBuilder & path,SkPoint & startPt)75 static SkPoint AddDegenQuad(SkPathBuilder& path, SkPoint& startPt) { 76 path.quadTo(startPt, startPt); 77 return startPt; 78 } 79 AddMoveDegenQuad(SkPathBuilder & path,SkPoint & startPt)80 static SkPoint AddMoveDegenQuad(SkPathBuilder& path, SkPoint& startPt) { 81 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 82 path.moveTo(moveToPt); 83 path.quadTo(moveToPt, moveToPt); 84 return moveToPt; 85 } 86 AddMoveDegenQuadClose(SkPathBuilder & path,SkPoint & startPt)87 static SkPoint AddMoveDegenQuadClose(SkPathBuilder& path, SkPoint& startPt) { 88 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 89 path.moveTo(moveToPt); 90 path.quadTo(moveToPt, moveToPt); 91 path.close(); 92 return moveToPt; 93 } 94 AddDegenCubic(SkPathBuilder & path,SkPoint & startPt)95 static SkPoint AddDegenCubic(SkPathBuilder& path, SkPoint& startPt) { 96 path.cubicTo(startPt, startPt, startPt); 97 return startPt; 98 } 99 AddMoveDegenCubic(SkPathBuilder & path,SkPoint & startPt)100 static SkPoint AddMoveDegenCubic(SkPathBuilder& path, SkPoint& startPt) { 101 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 102 path.moveTo(moveToPt); 103 path.cubicTo(moveToPt, moveToPt, moveToPt); 104 return moveToPt; 105 } 106 AddMoveDegenCubicClose(SkPathBuilder & path,SkPoint & startPt)107 static SkPoint AddMoveDegenCubicClose(SkPathBuilder& path, SkPoint& startPt) { 108 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 109 path.moveTo(moveToPt); 110 path.cubicTo(moveToPt, moveToPt, moveToPt); 111 path.close(); 112 return moveToPt; 113 } 114 AddClose(SkPathBuilder & path,SkPoint & startPt)115 static SkPoint AddClose(SkPathBuilder& path, SkPoint& startPt) { 116 path.close(); 117 return startPt; 118 } 119 AddLine(SkPathBuilder & path,SkPoint & startPt)120 static SkPoint AddLine(SkPathBuilder& path, SkPoint& startPt) { 121 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0); 122 path.lineTo(endPt); 123 return endPt; 124 } 125 AddMoveLine(SkPathBuilder & path,SkPoint & startPt)126 static SkPoint AddMoveLine(SkPathBuilder& path, SkPoint& startPt) { 127 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 128 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); 129 path.moveTo(moveToPt); 130 path.lineTo(endPt); 131 return endPt; 132 } 133 AddMoveLineClose(SkPathBuilder & path,SkPoint & startPt)134 static SkPoint AddMoveLineClose(SkPathBuilder& path, SkPoint& startPt) { 135 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 136 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); 137 path.moveTo(moveToPt); 138 path.lineTo(endPt); 139 path.close(); 140 return endPt; 141 } 142 AddQuad(SkPathBuilder & path,SkPoint & startPt)143 static SkPoint AddQuad(SkPathBuilder& path, SkPoint& startPt) { 144 SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1); 145 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0); 146 path.quadTo(midPt, endPt); 147 return endPt; 148 } 149 AddMoveQuad(SkPathBuilder & path,SkPoint & startPt)150 static SkPoint AddMoveQuad(SkPathBuilder& path, SkPoint& startPt) { 151 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 152 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1); 153 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); 154 path.moveTo(moveToPt); 155 path.quadTo(midPt, endPt); 156 return endPt; 157 } 158 AddMoveQuadClose(SkPathBuilder & path,SkPoint & startPt)159 static SkPoint AddMoveQuadClose(SkPathBuilder& path, SkPoint& startPt) { 160 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 161 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1); 162 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); 163 path.moveTo(moveToPt); 164 path.quadTo(midPt, endPt); 165 path.close(); 166 return endPt; 167 } 168 AddCubic(SkPathBuilder & path,SkPoint & startPt)169 static SkPoint AddCubic(SkPathBuilder& path, SkPoint& startPt) { 170 SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1); 171 SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1); 172 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0); 173 path.cubicTo(t1Pt, t2Pt, endPt); 174 return endPt; 175 } 176 AddMoveCubic(SkPathBuilder & path,SkPoint & startPt)177 static SkPoint AddMoveCubic(SkPathBuilder& path, SkPoint& startPt) { 178 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 179 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1); 180 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1); 181 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); 182 path.moveTo(moveToPt); 183 path.cubicTo(t1Pt, t2Pt, endPt); 184 return endPt; 185 } 186 AddMoveCubicClose(SkPathBuilder & path,SkPoint & startPt)187 static SkPoint AddMoveCubicClose(SkPathBuilder& path, SkPoint& startPt) { 188 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1); 189 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1); 190 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1); 191 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0); 192 path.moveTo(moveToPt); 193 path.cubicTo(t1Pt, t2Pt, endPt); 194 path.close(); 195 return endPt; 196 } 197 drawPath(SkPath path,SkCanvas * canvas,SkColor color,const SkRect & clip,SkPaint::Cap cap,SkPaint::Join join,SkPaint::Style style,SkPathFillType fill,SkScalar strokeWidth)198 void drawPath(SkPath path, SkCanvas* canvas, SkColor color, 199 const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join, 200 SkPaint::Style style, SkPathFillType fill, 201 SkScalar strokeWidth) { 202 path.setFillType(fill); 203 SkPaint paint; 204 paint.setStrokeCap(cap); 205 paint.setStrokeWidth(strokeWidth); 206 paint.setStrokeJoin(join); 207 paint.setColor(color); 208 paint.setStyle(style); 209 canvas->save(); 210 canvas->clipRect(clip); 211 canvas->drawPath(path, paint); 212 canvas->restore(); 213 } 214 onDraw(SkCanvas * canvas)215 void onDraw(SkCanvas* canvas) override { 216 constexpr AddSegmentFunc gSegmentFunctions[] = { 217 AddMove, 218 AddMoveClose, 219 AddDegenLine, 220 AddMoveDegenLine, 221 AddMoveDegenLineClose, 222 AddDegenQuad, 223 AddMoveDegenQuad, 224 AddMoveDegenQuadClose, 225 AddDegenCubic, 226 AddMoveDegenCubic, 227 AddMoveDegenCubicClose, 228 AddClose, 229 AddLine, 230 AddMoveLine, 231 AddMoveLineClose, 232 AddQuad, 233 AddMoveQuad, 234 AddMoveQuadClose, 235 AddCubic, 236 AddMoveCubic, 237 AddMoveCubicClose 238 }; 239 const char* gSegmentNames[] = { 240 "Move", 241 "MoveClose", 242 "DegenLine", 243 "MoveDegenLine", 244 "MoveDegenLineClose", 245 "DegenQuad", 246 "MoveDegenQuad", 247 "MoveDegenQuadClose", 248 "DegenCubic", 249 "MoveDegenCubic", 250 "MoveDegenCubicClose", 251 "Close", 252 "Line", 253 "MoveLine", 254 "MoveLineClose", 255 "Quad", 256 "MoveQuad", 257 "MoveQuadClose", 258 "Cubic", 259 "MoveCubic", 260 "MoveCubicClose" 261 }; 262 263 struct FillAndName { 264 SkPathFillType fFill; 265 const char* fName; 266 }; 267 constexpr FillAndName gFills[] = { 268 {SkPathFillType::kWinding, "Winding"}, 269 {SkPathFillType::kEvenOdd, "Even / Odd"}, 270 {SkPathFillType::kInverseWinding, "Inverse Winding"}, 271 {SkPathFillType::kInverseEvenOdd, "Inverse Even / Odd"} 272 }; 273 struct StyleAndName { 274 SkPaint::Style fStyle; 275 const char* fName; 276 }; 277 constexpr StyleAndName gStyles[] = { 278 {SkPaint::kFill_Style, "Fill"}, 279 {SkPaint::kStroke_Style, "Stroke 10"}, 280 {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"} 281 }; 282 struct CapAndName { 283 SkPaint::Cap fCap; 284 SkPaint::Join fJoin; 285 const char* fName; 286 }; 287 constexpr CapAndName gCaps[] = { 288 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"}, 289 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"}, 290 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"} 291 }; 292 293 SkPaint titlePaint; 294 titlePaint.setColor(SK_ColorBLACK); 295 titlePaint.setAntiAlias(true); 296 SkFont font(ToolUtils::create_portable_typeface(), 15); 297 const char title[] = "Random Paths Drawn Into Rectangle Clips With " 298 "Indicated Style, Fill and Linecaps, " 299 "with Stroke width 6"; 300 canvas->drawString(title, 20, 20, font, titlePaint); 301 302 SkRandom rand; 303 SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1); 304 canvas->save(); 305 canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title 306 canvas->save(); 307 unsigned numSegments = std::size(gSegmentFunctions); 308 unsigned numCaps = std::size(gCaps); 309 unsigned numStyles = std::size(gStyles); 310 unsigned numFills = std::size(gFills); 311 for (size_t row = 0; row < 6; ++row) { 312 if (0 < row) { 313 canvas->translate(0, rect.height() + 100*SK_Scalar1); 314 } 315 canvas->save(); 316 for (size_t column = 0; column < 4; ++column) { 317 if (0 < column) { 318 canvas->translate(rect.width() + 4*SK_Scalar1, 0); 319 } 320 321 SkColor color = ToolUtils::color_to_565(0xff007000); 322 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles]; 323 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps]; 324 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills]; 325 unsigned s1 = (rand.nextU() >> 16) % numSegments; 326 unsigned s2 = (rand.nextU() >> 16) % numSegments; 327 unsigned s3 = (rand.nextU() >> 16) % numSegments; 328 unsigned s4 = (rand.nextU() >> 16) % numSegments; 329 unsigned s5 = (rand.nextU() >> 16) % numSegments; 330 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0); 331 SkPathBuilder path; 332 pt = gSegmentFunctions[s1](path, pt); 333 pt = gSegmentFunctions[s2](path, pt); 334 pt = gSegmentFunctions[s3](path, pt); 335 pt = gSegmentFunctions[s4](path, pt); 336 pt = gSegmentFunctions[s5](path, pt); 337 338 this->drawPath(path.detach(), canvas, color, rect, 339 cap.fCap, cap.fJoin, style.fStyle, 340 fill.fFill, SK_Scalar1*6); 341 342 SkPaint rectPaint; 343 rectPaint.setColor(SK_ColorBLACK); 344 rectPaint.setStyle(SkPaint::kStroke_Style); 345 rectPaint.setStrokeWidth(-1); 346 rectPaint.setAntiAlias(true); 347 canvas->drawRect(rect, rectPaint); 348 349 SkPaint labelPaint; 350 labelPaint.setColor(color); 351 labelPaint.setAntiAlias(true); 352 font.setSize(10); 353 canvas->drawString(style.fName, 0, rect.height() + 12, font, labelPaint); 354 canvas->drawString(fill.fName, 0, rect.height() + 24, font, labelPaint); 355 canvas->drawString(cap.fName, 0, rect.height() + 36, font, labelPaint); 356 canvas->drawString(gSegmentNames[s1], 0, rect.height() + 48, font, labelPaint); 357 canvas->drawString(gSegmentNames[s2], 0, rect.height() + 60, font, labelPaint); 358 canvas->drawString(gSegmentNames[s3], 0, rect.height() + 72, font, labelPaint); 359 canvas->drawString(gSegmentNames[s4], 0, rect.height() + 84, font, labelPaint); 360 canvas->drawString(gSegmentNames[s5], 0, rect.height() + 96, font, labelPaint); 361 } 362 canvas->restore(); 363 } 364 canvas->restore(); 365 canvas->restore(); 366 } 367 }; 368 369 ////////////////////////////////////////////////////////////////////////////// 370 371 DEF_GM( return new DegenerateSegmentsGM; ) 372 373 } // namespace skiagm 374