xref: /aosp_15_r20/external/skia/gm/convexpaths.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/SkMatrix.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPathBuilder.h"
14 #include "include/core/SkRRect.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/SkTypes.h"
20 #include "include/private/base/SkTArray.h"
21 #include "src/base/SkRandom.h"
22 
23 using namespace skia_private;
24 
25 namespace {
26 
27 class SkDoOnce {
28 public:
SkDoOnce()29     SkDoOnce() { fDidOnce = false; }
30     // Make noncopyable
31     SkDoOnce(SkDoOnce&) = delete;
32     SkDoOnce& operator=(SkDoOnce&) = delete;
33 
needToDo() const34     bool needToDo() const { return !fDidOnce; }
alreadyDone() const35     bool alreadyDone() const { return fDidOnce; }
accomplished()36     void accomplished() {
37         SkASSERT(!fDidOnce);
38         fDidOnce = true;
39     }
40 
41 private:
42     bool fDidOnce;
43 };
44 
45 class ConvexPathsGM : public skiagm::GM {
46     SkDoOnce fOnce;
47 
onOnceBeforeDraw()48     void onOnceBeforeDraw() override { this->setBGColor(0xFF000000); }
49 
getName() const50     SkString getName() const override { return SkString("convexpaths"); }
51 
getISize()52     SkISize getISize() override { return {1200, 1100}; }
53 
makePaths()54     void makePaths() {
55         if (fOnce.alreadyDone()) {
56             return;
57         }
58         fOnce.accomplished();
59 
60         SkPathBuilder b;
61         fPaths.push_back(b.moveTo(0, 0)
62                           .quadTo(50, 100, 0, 100)
63                           .lineTo(0, 0)
64                           .detach());
65 
66         fPaths.push_back(b.moveTo(0, 50)
67                           .quadTo(50, 0, 100, 50)
68                           .quadTo(50, 100, 0, 50)
69                           .detach());
70 
71         fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCW));
72         fPaths.push_back(SkPath::Rect({0, 0, 100, 100}, SkPathDirection::kCCW));
73         fPaths.push_back(SkPath::Circle(50, 50, 50, SkPathDirection::kCW));
74         fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 50, 100), SkPathDirection::kCW));
75         fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 100, 5), SkPathDirection::kCCW));
76         fPaths.push_back(SkPath::Oval(SkRect::MakeXYWH(0, 0, 1, 100), SkPathDirection::kCCW));
77         fPaths.push_back(SkPath::RRect(SkRRect::MakeRectXY({0, 0, 100, 100}, 40, 20),
78                                        SkPathDirection::kCW));
79 
80         // large number of points
81         static constexpr int kLength = 100;
82         static constexpr int kPtsPerSide = (1 << 12);
83 
84         b.moveTo(0, 0);
85         for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo.
86             b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0);
87         }
88         for (int i = 0; i < kPtsPerSide; ++i) {
89             b.lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide);
90         }
91         for (int i = kPtsPerSide; i > 0; --i) {
92             b.lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength);
93         }
94         for (int i = kPtsPerSide; i > 0; --i) {
95             b.lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide);
96         }
97         fPaths.push_back(b.detach());
98 
99         // shallow diagonals
100         fPaths.push_back(SkPath::Polygon({{0,0}, {100,1}, {98,100}, {3,96}}, false));
101 
102         fPaths.push_back(b.arcTo(SkRect::MakeXYWH(0, 0, 50, 100), 25, 130, false)
103                           .detach());
104 
105         // cubics
106         fPaths.push_back(b.cubicTo(  1,  1, 10,  90, 0, 100).detach());
107         fPaths.push_back(b.cubicTo(100, 50, 20, 100, 0,   0).detach());
108 
109         // path that has a cubic with a repeated first control point and
110         // a repeated last control point.
111         fPaths.push_back(b.moveTo(10, 10)
112                           .cubicTo(10, 10, 10, 0, 20, 0)
113                           .lineTo(40, 0)
114                           .cubicTo(40, 0, 50, 0, 50, 10)
115                           .detach());
116 
117         // path that has two cubics with repeated middle control points.
118         fPaths.push_back(b.moveTo(10, 10)
119                           .cubicTo(10, 0, 10, 0, 20, 0)
120                           .lineTo(40, 0)
121                           .cubicTo(50, 0, 50, 0, 50, 10)
122                           .detach());
123 
124         // cubic where last three points are almost a line
125         fPaths.push_back(b.moveTo(0, 228.0f/8)
126                           .cubicTo( 628.0f/ 8,  82.0f/8,
127                                    1255.0f/ 8, 141.0f/8,
128                                    1883.0f/ 8, 202.0f/8)
129                           .detach());
130 
131         // flat cubic where the at end point tangents both point outward.
132         fPaths.push_back(b.moveTo(10, 0)
133                           .cubicTo(0, 1, 30, 1, 20, 0)
134                           .detach());
135 
136         // flat cubic where initial tangent is in, end tangent out
137         fPaths.push_back(b.moveTo(0, 0)
138                           .cubicTo(10, 1, 30, 1, 20, 0)
139                           .detach());
140 
141         // flat cubic where initial tangent is out, end tangent in
142         fPaths.push_back(b.moveTo(10, 0)
143                           .cubicTo(0, 1, 20, 1, 30, 0)
144                           .detach());
145 
146         // triangle where one edge is a degenerate quad
147         fPaths.push_back(b.moveTo(8.59375f, 45)
148                           .quadTo(16.9921875f,   45,
149                                   31.25f,        45)
150                           .lineTo(100,          100)
151                           .lineTo(8.59375f,      45)
152                           .detach());
153 
154         // triangle where one edge is a quad with a repeated point
155         fPaths.push_back(b.moveTo(0, 25)
156                           .lineTo(50, 0)
157                           .quadTo(50, 50, 50, 50)
158                           .detach());
159 
160         // triangle where one edge is a cubic with a 2x repeated point
161         fPaths.push_back(b.moveTo(0, 25)
162                           .lineTo(50, 0)
163                           .cubicTo(50, 0, 50, 50, 50, 50)
164                           .detach());
165 
166         // triangle where one edge is a quad with a nearly repeated point
167         fPaths.push_back(b.moveTo(0, 25)
168                           .lineTo(50, 0)
169                           .quadTo(50, 49.95f, 50, 50)
170                           .detach());
171 
172         // triangle where one edge is a cubic with a 3x nearly repeated point
173         fPaths.push_back(b.moveTo(0, 25)
174                           .lineTo(50, 0)
175                           .cubicTo(50, 49.95f, 50, 49.97f, 50, 50)
176                           .detach());
177 
178         // triangle where there is a point degenerate cubic at one corner
179         fPaths.push_back(b.moveTo(0, 25)
180                           .lineTo(50, 0)
181                           .lineTo(50, 50)
182                           .cubicTo(50, 50, 50, 50, 50, 50)
183                           .detach());
184 
185         // point line
186         fPaths.push_back(SkPath::Line({50, 50}, {50, 50}));
187 
188         // point quad
189         fPaths.push_back(b.moveTo(50, 50)
190                           .quadTo(50, 50, 50, 50)
191                           .detach());
192 
193         // point cubic
194         fPaths.push_back(b.moveTo(50, 50)
195                           .cubicTo(50, 50, 50, 50, 50, 50)
196                           .detach());
197 
198         // moveTo only paths
199         fPaths.push_back(b.moveTo(0, 0)
200                           .moveTo(0, 0)
201                           .moveTo(1, 1)
202                           .moveTo(1, 1)
203                           .moveTo(10, 10)
204                           .detach());
205 
206         fPaths.push_back(b.moveTo(0, 0)
207                           .moveTo(0, 0)
208                           .detach());
209 
210         // line degenerate
211         fPaths.push_back(b.lineTo(100, 100).detach());
212         fPaths.push_back(b.quadTo(100, 100, 0, 0).detach());
213         fPaths.push_back(b.quadTo(100, 100, 50, 50).detach());
214         fPaths.push_back(b.quadTo(50, 50, 100, 100).detach());
215         fPaths.push_back(b.cubicTo(0, 0, 0, 0, 100, 100).detach());
216 
217         // skbug.com/8928
218         fPaths.push_back(b.moveTo(16.875f, 192.594f)
219                           .cubicTo(45.625f, 192.594f, 74.375f, 192.594f, 103.125f, 192.594f)
220                           .cubicTo(88.75f, 167.708f, 74.375f, 142.823f, 60, 117.938f)
221                           .cubicTo(45.625f, 142.823f, 31.25f, 167.708f, 16.875f, 192.594f)
222                           .close()
223                           .detach());
224         SkMatrix m;
225         m.setAll(0.1f, 0, -1, 0, 0.115207f, -2.64977f, 0, 0, 1);
226         fPaths.back().transform(m);
227 
228         // small circle. This is listed last so that it has device coords far
229         // from the origin (small area relative to x,y values).
230         fPaths.push_back(SkPath::Circle(0, 0, 1.2f));
231     }
232 
onDraw(SkCanvas * canvas)233     void onDraw(SkCanvas* canvas) override {
234         this->makePaths();
235 
236         SkPaint paint;
237         paint.setAntiAlias(true);
238         SkRandom rand;
239         canvas->translate(20, 20);
240 
241         // As we've added more paths this has gotten pretty big. Scale the whole thing down.
242         canvas->scale(2.0f/3, 2.0f/3);
243 
244         for (int i = 0; i < fPaths.size(); ++i) {
245             canvas->save();
246             // position the path, and make it at off-integer coords.
247             canvas->translate(200.0f * (i % 5) + 1.0f/10,
248                               200.0f * (i / 5) + 9.0f/10);
249             SkColor color = rand.nextU();
250             color |= 0xff000000;
251             paint.setColor(color);
252 #if 0       // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is
253             // debugged.
254             SkASSERT(fPaths[i].isConvex());
255 #endif
256             canvas->drawPath(fPaths[i], paint);
257             canvas->restore();
258         }
259     }
260 
261     TArray<SkPath> fPaths;
262 };
263 }  // namespace
264 
265 DEF_GM( return new ConvexPathsGM; )
266