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