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