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