convexpaths.cpp revision 4b413c8bb123e42ca4b9c7bfa6bc2167283cb84c
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
12class SkOnce : SkNoncopyable {
13public:
14    SkOnce() { fDidOnce = false; }
15
16    bool needToDo() const { return !fDidOnce; }
17    bool alreadyDone() const { return fDidOnce; }
18    void accomplished() {
19        SkASSERT(!fDidOnce);
20        fDidOnce = true;
21    }
22
23private:
24    bool fDidOnce;
25};
26
27namespace skiagm {
28
29class ConvexPathsGM : public GM {
30    SkOnce fOnce;
31public:
32    ConvexPathsGM() {
33        this->setBGColor(0xFF000000);
34    }
35
36protected:
37    virtual SkString onShortName() {
38        return SkString("convexpaths");
39    }
40
41
42    virtual SkISize onISize() {
43        return make_isize(1200, 1100);
44    }
45
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
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
287private:
288    typedef GM INHERITED;
289    SkTArray<SkPath> fPaths;
290};
291
292//////////////////////////////////////////////////////////////////////////////
293
294static GM* MyFactory(void*) { return new ConvexPathsGM; }
295static GMRegistry reg(MyFactory);
296
297}
298