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