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