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