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