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