• 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/SkPath.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         fPaths.push_back().moveTo(0, 0);
57         fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
58                              0, 100 * SK_Scalar1);
59         fPaths.back().lineTo(0, 0);
60 
61         fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
62         fPaths.back().quadTo(50 * SK_Scalar1, 0,
63                              100 * SK_Scalar1, 50 * SK_Scalar1);
64         fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
65                              0, 50 * SK_Scalar1);
66 
67         fPaths.push_back().addRect(0, 0,
68                                    100 * SK_Scalar1, 100 * SK_Scalar1,
69                                    SkPath::kCW_Direction);
70 
71         fPaths.push_back().addRect(0, 0,
72                                    100 * SK_Scalar1, 100 * SK_Scalar1,
73                                    SkPath::kCCW_Direction);
74 
75         fPaths.push_back().addCircle(50  * SK_Scalar1, 50  * SK_Scalar1,
76                                      50  * SK_Scalar1, SkPath::kCW_Direction);
77 
78 
79         fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
80                                                     50 * SK_Scalar1,
81                                                     100 * SK_Scalar1),
82                                    SkPath::kCW_Direction);
83 
84         fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
85                                                     100 * SK_Scalar1,
86                                                     5 * SK_Scalar1),
87                                    SkPath::kCCW_Direction);
88 
89         fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
90                                                     SK_Scalar1,
91                                                     100 * SK_Scalar1),
92                                                     SkPath::kCCW_Direction);
93 
94         fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
95                                                          SK_Scalar1 * 100,
96                                                          SK_Scalar1 * 100),
97                                         40 * SK_Scalar1, 20 * SK_Scalar1,
98                                         SkPath::kCW_Direction);
99 
100         // large number of points
101         enum {
102             kLength = 100,
103             kPtsPerSide = (1 << 12),
104         };
105         fPaths.push_back().moveTo(0, 0);
106         for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo.
107             fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0);
108         }
109         for (int i = 0; i < kPtsPerSide; ++i) {
110             fPaths.back().lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide);
111         }
112         for (int i = kPtsPerSide; i > 0; --i) {
113             fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength);
114         }
115         for (int i = kPtsPerSide; i > 0; --i) {
116             fPaths.back().lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide);
117         }
118 
119         // shallow diagonals
120         fPaths.push_back().lineTo(100 * SK_Scalar1, SK_Scalar1);
121         fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
122         fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
123 
124         fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
125                                                   50 * SK_Scalar1,
126                                                   100 * SK_Scalar1),
127                                                   25 * SK_Scalar1,  130 * SK_Scalar1, false);
128 
129         // cubics
130         fPaths.push_back().cubicTo( 1 * SK_Scalar1,  1 * SK_Scalar1,
131                                    10 * SK_Scalar1,  90 * SK_Scalar1,
132                                     0 * SK_Scalar1, 100 * SK_Scalar1);
133         fPaths.push_back().cubicTo(100 * SK_Scalar1,  50 * SK_Scalar1,
134                                     20 * SK_Scalar1, 100 * SK_Scalar1,
135                                      0 * SK_Scalar1,   0 * SK_Scalar1);
136 
137         // path that has a cubic with a repeated first control point and
138         // a repeated last control point.
139         fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
140         fPaths.back().cubicTo(10 * SK_Scalar1, 10 * SK_Scalar1,
141                               10 * SK_Scalar1, 0,
142                               20 * SK_Scalar1, 0);
143         fPaths.back().lineTo(40 * SK_Scalar1, 0);
144         fPaths.back().cubicTo(40 * SK_Scalar1, 0,
145                               50 * SK_Scalar1, 0,
146                               50 * SK_Scalar1, 10 * SK_Scalar1);
147 
148         // path that has two cubics with repeated middle control points.
149         fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
150         fPaths.back().cubicTo(10 * SK_Scalar1, 0,
151                               10 * SK_Scalar1, 0,
152                               20 * SK_Scalar1, 0);
153         fPaths.back().lineTo(40 * SK_Scalar1, 0);
154         fPaths.back().cubicTo(50 * SK_Scalar1, 0,
155                               50 * SK_Scalar1, 0,
156                               50 * SK_Scalar1, 10 * SK_Scalar1);
157 
158         // cubic where last three points are almost a line
159         fPaths.push_back().moveTo(0, 228 * SK_Scalar1 / 8);
160         fPaths.back().cubicTo(628 * SK_Scalar1 / 8, 82 * SK_Scalar1 / 8,
161                               1255 * SK_Scalar1 / 8, 141 * SK_Scalar1 / 8,
162                               1883 * SK_Scalar1 / 8, 202 * SK_Scalar1 / 8);
163 
164         // flat cubic where the at end point tangents both point outward.
165         fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
166         fPaths.back().cubicTo(0, SK_Scalar1,
167                               30 * SK_Scalar1, SK_Scalar1,
168                               20 * SK_Scalar1, 0);
169 
170         // flat cubic where initial tangent is in, end tangent out
171         fPaths.push_back().moveTo(0, 0 * SK_Scalar1);
172         fPaths.back().cubicTo(10 * SK_Scalar1, SK_Scalar1,
173                               30 * SK_Scalar1, SK_Scalar1,
174                               20 * SK_Scalar1, 0);
175 
176         // flat cubic where initial tangent is out, end tangent in
177         fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
178         fPaths.back().cubicTo(0, SK_Scalar1,
179                               20 * SK_Scalar1, SK_Scalar1,
180                               30 * SK_Scalar1, 0);
181 
182         // triangle where one edge is a degenerate quad
183         fPaths.push_back().moveTo(8.59375f, 45 * SK_Scalar1);
184         fPaths.back().quadTo(16.9921875f,   45 * SK_Scalar1,
185                              31.25f,        45 * SK_Scalar1);
186         fPaths.back().lineTo(100 * SK_Scalar1,              100 * SK_Scalar1);
187         fPaths.back().lineTo(8.59375f,      45 * SK_Scalar1);
188 
189         // triangle where one edge is a quad with a repeated point
190         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
191         fPaths.back().lineTo(50 * SK_Scalar1, 0);
192         fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1);
193 
194         // triangle where one edge is a cubic with a 2x repeated point
195         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
196         fPaths.back().lineTo(50 * SK_Scalar1, 0);
197         fPaths.back().cubicTo(50 * SK_Scalar1, 0,
198                               50 * SK_Scalar1, 50 * SK_Scalar1,
199                               50 * SK_Scalar1, 50 * SK_Scalar1);
200 
201         // triangle where one edge is a quad with a nearly repeated point
202         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
203         fPaths.back().lineTo(50 * SK_Scalar1, 0);
204         fPaths.back().quadTo(50 * SK_Scalar1, 49.95f,
205                              50 * SK_Scalar1, 50 * SK_Scalar1);
206 
207         // triangle where one edge is a cubic with a 3x nearly repeated point
208         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
209         fPaths.back().lineTo(50 * SK_Scalar1, 0);
210         fPaths.back().cubicTo(50 * SK_Scalar1, 49.95f,
211                               50 * SK_Scalar1, 49.97f,
212                               50 * SK_Scalar1, 50 * SK_Scalar1);
213 
214         // triangle where there is a point degenerate cubic at one corner
215         fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
216         fPaths.back().lineTo(50 * SK_Scalar1, 0);
217         fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
218         fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
219                               50 * SK_Scalar1, 50 * SK_Scalar1,
220                               50 * SK_Scalar1, 50 * SK_Scalar1);
221 
222         // point line
223         fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
224         fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
225 
226         // point quad
227         fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
228         fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
229                              50 * SK_Scalar1, 50 * SK_Scalar1);
230 
231         // point cubic
232         fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
233         fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
234                               50 * SK_Scalar1, 50 * SK_Scalar1,
235                               50 * SK_Scalar1, 50 * SK_Scalar1);
236 
237         // moveTo only paths
238         fPaths.push_back().moveTo(0, 0);
239         fPaths.back().moveTo(0, 0);
240         fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
241         fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
242         fPaths.back().moveTo(10 * SK_Scalar1, 10 * SK_Scalar1);
243 
244         fPaths.push_back().moveTo(0, 0);
245         fPaths.back().moveTo(0, 0);
246 
247         // line degenerate
248         fPaths.push_back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
249         fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1, 0, 0);
250         fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1,
251                                   50 * SK_Scalar1, 50 * SK_Scalar1);
252         fPaths.push_back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
253                                   100 * SK_Scalar1, 100 * SK_Scalar1);
254         fPaths.push_back().cubicTo(0, 0,
255                                    0, 0,
256                                    100 * SK_Scalar1, 100 * SK_Scalar1);
257 
258         // skbug.com/8928
259         fPaths.push_back().moveTo(16.875f, 192.594f);
260         fPaths.back().cubicTo(45.625f, 192.594f, 74.375f, 192.594f, 103.125f, 192.594f);
261         fPaths.back().cubicTo(88.75f, 167.708f, 74.375f, 142.823f, 60, 117.938f);
262         fPaths.back().cubicTo(45.625f, 142.823f, 31.25f, 167.708f, 16.875f, 192.594f);
263         fPaths.back().close();
264         SkMatrix m;
265         m.setAll(0.1f, 0, -1, 0, 0.115207f, -2.64977f, 0, 0, 1);
266         fPaths.back().transform(m);
267 
268         // small circle. This is listed last so that it has device coords far
269         // from the origin (small area relative to x,y values).
270         fPaths.push_back().addCircle(0, 0, 1.2f);
271     }
272 
onDraw(SkCanvas * canvas)273     void onDraw(SkCanvas* canvas) override {
274         this->makePaths();
275 
276         SkPaint paint;
277         paint.setAntiAlias(true);
278         SkRandom rand;
279         canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
280 
281         // As we've added more paths this has gotten pretty big. Scale the whole thing down.
282         canvas->scale(2 * SK_Scalar1 / 3, 2 * SK_Scalar1 / 3);
283 
284         for (int i = 0; i < fPaths.count(); ++i) {
285             canvas->save();
286             // position the path, and make it at off-integer coords.
287             canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 10,
288                               SK_Scalar1 * 200 * (i / 5) + 9 * SK_Scalar1 / 10);
289             SkColor color = rand.nextU();
290             color |= 0xff000000;
291             paint.setColor(color);
292 #if 0       // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is
293             // debugged.
294             SkASSERT(fPaths[i].isConvex());
295 #endif
296             canvas->drawPath(fPaths[i], paint);
297             canvas->restore();
298         }
299     }
300 
301     SkTArray<SkPath> fPaths;
302 };
303 }  // namespace
304 
305 DEF_GM( return new ConvexPathsGM; )
306