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
onGetFlags() const25 virtual uint32_t onGetFlags() const SK_OVERRIDE {
26 return kSkipTiled_Flag;
27 }
28
onShortName()29 SkString onShortName() {
30 return SkString("degeneratesegments");
31 }
32
onISize()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.
AddMove(SkPath & path,SkPoint & startPt)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
AddMoveClose(SkPath & path,SkPoint & startPt)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
AddDegenLine(SkPath & path,SkPoint & startPt)53 static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
54 path.lineTo(startPt);
55 return startPt;
56 }
57
AddMoveDegenLine(SkPath & path,SkPoint & startPt)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
AddMoveDegenLineClose(SkPath & path,SkPoint & startPt)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
AddDegenQuad(SkPath & path,SkPoint & startPt)73 static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
74 path.quadTo(startPt, startPt);
75 return startPt;
76 }
77
AddMoveDegenQuad(SkPath & path,SkPoint & startPt)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
AddMoveDegenQuadClose(SkPath & path,SkPoint & startPt)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
AddDegenCubic(SkPath & path,SkPoint & startPt)93 static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
94 path.cubicTo(startPt, startPt, startPt);
95 return startPt;
96 }
97
AddMoveDegenCubic(SkPath & path,SkPoint & startPt)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
AddMoveDegenCubicClose(SkPath & path,SkPoint & startPt)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
AddClose(SkPath & path,SkPoint & startPt)113 static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
114 path.close();
115 return startPt;
116 }
117
AddLine(SkPath & path,SkPoint & startPt)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
AddMoveLine(SkPath & path,SkPoint & startPt)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
AddMoveLineClose(SkPath & path,SkPoint & startPt)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
AddQuad(SkPath & path,SkPoint & startPt)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
AddMoveQuad(SkPath & path,SkPoint & startPt)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
AddMoveQuadClose(SkPath & path,SkPoint & startPt)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
AddCubic(SkPath & path,SkPoint & startPt)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
AddMoveCubic(SkPath & path,SkPoint & startPt)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
AddMoveCubicClose(SkPath & path,SkPoint & startPt)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
drawPath(SkPath & path,SkCanvas * canvas,SkColor color,const SkRect & clip,SkPaint::Cap cap,SkPaint::Join join,SkPaint::Style style,SkPath::FillType fill,SkScalar strokeWidth)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
onDraw(SkCanvas * canvas)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 titlePaint.setLCDRenderText(true);
295 titlePaint.setTextSize(15 * SK_Scalar1);
296 const char title[] = "Random Paths Drawn Into Rectangle Clips With "
297 "Indicated Style, Fill and Linecaps, "
298 "with Stroke width 6";
299 canvas->drawText(title, strlen(title),
300 20 * SK_Scalar1,
301 20 * SK_Scalar1,
302 titlePaint);
303
304 SkLCGRandom rand;
305 SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
306 canvas->save();
307 canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
308 canvas->save();
309 unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
310 unsigned numCaps = SK_ARRAY_COUNT(gCaps);
311 unsigned numStyles = SK_ARRAY_COUNT(gStyles);
312 unsigned numFills = SK_ARRAY_COUNT(gFills);
313 for (size_t row = 0; row < 6; ++row) {
314 if (0 < row) {
315 canvas->translate(0, rect.height() + 100*SK_Scalar1);
316 }
317 canvas->save();
318 for (size_t column = 0; column < 4; ++column) {
319 if (0 < column) {
320 canvas->translate(rect.width() + 4*SK_Scalar1, 0);
321 }
322
323 SkColor color = 0xff007000;
324 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
325 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
326 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
327 SkPath path;
328 unsigned s1 = (rand.nextU() >> 16) % numSegments;
329 unsigned s2 = (rand.nextU() >> 16) % numSegments;
330 unsigned s3 = (rand.nextU() >> 16) % numSegments;
331 unsigned s4 = (rand.nextU() >> 16) % numSegments;
332 unsigned s5 = (rand.nextU() >> 16) % numSegments;
333 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
334 pt = gSegmentFunctions[s1](path, pt);
335 pt = gSegmentFunctions[s2](path, pt);
336 pt = gSegmentFunctions[s3](path, pt);
337 pt = gSegmentFunctions[s4](path, pt);
338 pt = gSegmentFunctions[s5](path, pt);
339
340 this->drawPath(path, canvas, color, rect,
341 cap.fCap, cap.fJoin, style.fStyle,
342 fill.fFill, SK_Scalar1*6);
343
344 SkPaint rectPaint;
345 rectPaint.setColor(SK_ColorBLACK);
346 rectPaint.setStyle(SkPaint::kStroke_Style);
347 rectPaint.setStrokeWidth(-1);
348 rectPaint.setAntiAlias(true);
349 canvas->drawRect(rect, rectPaint);
350
351 SkPaint labelPaint;
352 labelPaint.setColor(color);
353 labelPaint.setAntiAlias(true);
354 labelPaint.setLCDRenderText(true);
355 labelPaint.setTextSize(10 * SK_Scalar1);
356 canvas->drawText(style.fName,
357 strlen(style.fName),
358 0, rect.height() + 12 * SK_Scalar1,
359 labelPaint);
360 canvas->drawText(fill.fName,
361 strlen(fill.fName),
362 0, rect.height() + 24 * SK_Scalar1,
363 labelPaint);
364 canvas->drawText(cap.fName,
365 strlen(cap.fName),
366 0, rect.height() + 36 * SK_Scalar1,
367 labelPaint);
368 canvas->drawText(gSegmentNames[s1],
369 strlen(gSegmentNames[s1]),
370 0, rect.height() + 48 * SK_Scalar1,
371 labelPaint);
372 canvas->drawText(gSegmentNames[s2],
373 strlen(gSegmentNames[s2]),
374 0, rect.height() + 60 * SK_Scalar1,
375 labelPaint);
376 canvas->drawText(gSegmentNames[s3],
377 strlen(gSegmentNames[s3]),
378 0, rect.height() + 72 * SK_Scalar1,
379 labelPaint);
380 canvas->drawText(gSegmentNames[s4],
381 strlen(gSegmentNames[s4]),
382 0, rect.height() + 84 * SK_Scalar1,
383 labelPaint);
384 canvas->drawText(gSegmentNames[s5],
385 strlen(gSegmentNames[s5]),
386 0, rect.height() + 96 * SK_Scalar1,
387 labelPaint);
388 }
389 canvas->restore();
390 }
391 canvas->restore();
392 canvas->restore();
393 }
394
395 private:
396 typedef GM INHERITED;
397 };
398
399 //////////////////////////////////////////////////////////////////////////////
400
MyFactory(void *)401 static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
402 static GMRegistry reg(MyFactory);
403
404 }
405