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 SkISize::Make(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         sk_tool_utils::set_portable_typeface(&titlePaint);
291         titlePaint.setLCDRenderText(true);
292         titlePaint.setTextSize(15 * SK_Scalar1);
293         const char title[] = "Random Paths Drawn Into Rectangle Clips With "
294                              "Indicated Style, Fill and Linecaps, "
295                              "with Stroke width 6";
296         canvas->drawText(title, strlen(title),
297                             20 * SK_Scalar1,
298                             20 * SK_Scalar1,
299                             titlePaint);
300 
301         SkRandom rand;
302         SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
303         canvas->save();
304         canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
305         canvas->save();
306         unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
307         unsigned numCaps = SK_ARRAY_COUNT(gCaps);
308         unsigned numStyles = SK_ARRAY_COUNT(gStyles);
309         unsigned numFills = SK_ARRAY_COUNT(gFills);
310         for (size_t row = 0; row < 6; ++row) {
311             if (0 < row) {
312                 canvas->translate(0, rect.height() + 100*SK_Scalar1);
313             }
314             canvas->save();
315             for (size_t column = 0; column < 4; ++column) {
316                 if (0 < column) {
317                     canvas->translate(rect.width() + 4*SK_Scalar1, 0);
318                 }
319 
320                 SkColor color = 0xff007000;
321                 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
322                 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
323                 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
324                 SkPath path;
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                 pt = gSegmentFunctions[s1](path, pt);
332                 pt = gSegmentFunctions[s2](path, pt);
333                 pt = gSegmentFunctions[s3](path, pt);
334                 pt = gSegmentFunctions[s4](path, pt);
335                 pt = gSegmentFunctions[s5](path, pt);
336 
337                 this->drawPath(path, canvas, color, rect,
338                                cap.fCap, cap.fJoin, style.fStyle,
339                                fill.fFill, SK_Scalar1*6);
340 
341                 SkPaint rectPaint;
342                 rectPaint.setColor(SK_ColorBLACK);
343                 rectPaint.setStyle(SkPaint::kStroke_Style);
344                 rectPaint.setStrokeWidth(-1);
345                 rectPaint.setAntiAlias(true);
346                 canvas->drawRect(rect, rectPaint);
347 
348                 SkPaint labelPaint;
349                 labelPaint.setColor(color);
350                 labelPaint.setAntiAlias(true);
351                 sk_tool_utils::set_portable_typeface(&labelPaint);
352                 labelPaint.setLCDRenderText(true);
353                 labelPaint.setTextSize(10 * SK_Scalar1);
354                 canvas->drawText(style.fName,
355                                  strlen(style.fName),
356                                  0, rect.height() + 12 * SK_Scalar1,
357                                  labelPaint);
358                 canvas->drawText(fill.fName,
359                                  strlen(fill.fName),
360                                  0, rect.height() + 24 * SK_Scalar1,
361                                  labelPaint);
362                 canvas->drawText(cap.fName,
363                                  strlen(cap.fName),
364                                  0, rect.height() + 36 * SK_Scalar1,
365                                  labelPaint);
366                 canvas->drawText(gSegmentNames[s1],
367                                  strlen(gSegmentNames[s1]),
368                                  0, rect.height() + 48 * SK_Scalar1,
369                                  labelPaint);
370                 canvas->drawText(gSegmentNames[s2],
371                                  strlen(gSegmentNames[s2]),
372                                  0, rect.height() + 60 * SK_Scalar1,
373                                  labelPaint);
374                 canvas->drawText(gSegmentNames[s3],
375                                  strlen(gSegmentNames[s3]),
376                                  0, rect.height() + 72 * SK_Scalar1,
377                                  labelPaint);
378                 canvas->drawText(gSegmentNames[s4],
379                                  strlen(gSegmentNames[s4]),
380                                  0, rect.height() + 84 * SK_Scalar1,
381                                  labelPaint);
382                 canvas->drawText(gSegmentNames[s5],
383                                  strlen(gSegmentNames[s5]),
384                                  0, rect.height() + 96 * SK_Scalar1,
385                                  labelPaint);
386             }
387             canvas->restore();
388         }
389         canvas->restore();
390         canvas->restore();
391     }
392 
393 private:
394     typedef GM INHERITED;
395 };
396 
397 //////////////////////////////////////////////////////////////////////////////
398 
MyFactory(void *)399 static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
400 static GMRegistry reg(MyFactory);
401 
402 }
403