convexpaths.cpp revision a51ab8416db9772a2eae3122f4f69801642daeb5
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, 900);
44    }
45
46    void makePaths() {
47        if (fOnce.alreadyDone()) {
48            return;
49        }
50        fOnce.accomplished();
51
52        // CW
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        // CCW
59        fPaths.push_back().moveTo(0, 0);
60        fPaths.back().lineTo(0, 100 * SK_Scalar1);
61        fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
62                             0, 0);
63
64        // CW
65        fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
66        fPaths.back().quadTo(50 * SK_Scalar1, 0,
67                             100 * SK_Scalar1, 50 * SK_Scalar1);
68        fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
69                             0, 50 * SK_Scalar1);
70
71        // CCW
72        fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
73        fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
74                             100 * SK_Scalar1, 50 * SK_Scalar1);
75        fPaths.back().quadTo(50 * SK_Scalar1, 0,
76                             0, 50 * SK_Scalar1);
77
78        fPaths.push_back().addRect(0, 0,
79                                   100 * SK_Scalar1, 100 * SK_Scalar1,
80                                   SkPath::kCW_Direction);
81
82        fPaths.push_back().addRect(0, 0,
83                                   100 * SK_Scalar1, 100 * SK_Scalar1,
84                                   SkPath::kCCW_Direction);
85
86        fPaths.push_back().addCircle(50  * SK_Scalar1, 50  * SK_Scalar1,
87                                     50  * SK_Scalar1, SkPath::kCW_Direction);
88
89        fPaths.push_back().addCircle(50  * SK_Scalar1, 50  * SK_Scalar1,
90                                     40  * SK_Scalar1, SkPath::kCCW_Direction);
91
92        fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
93                                                    50 * SK_Scalar1,
94                                                    100 * SK_Scalar1),
95                                   SkPath::kCW_Direction);
96
97        fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
98                                                    100 * SK_Scalar1,
99                                                    50 * SK_Scalar1),
100                                   SkPath::kCCW_Direction);
101
102        fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
103                                                    100 * SK_Scalar1,
104                                                    5 * SK_Scalar1),
105                                   SkPath::kCCW_Direction);
106
107        fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
108                                                    SK_Scalar1,
109                                                    100 * SK_Scalar1),
110                                   SkPath::kCCW_Direction);
111
112        fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
113                                                         SK_Scalar1 * 100,
114                                                         SK_Scalar1 * 100),
115                                        40 * SK_Scalar1, 20 * SK_Scalar1,
116                                        SkPath::kCW_Direction);
117
118        fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
119                                                         SK_Scalar1 * 100,
120                                                         SK_Scalar1 * 100),
121                                        20 * SK_Scalar1, 40 * SK_Scalar1,
122                                        SkPath::kCCW_Direction);
123
124        // shallow diagonals
125        fPaths.push_back().lineTo(100 * SK_Scalar1, SK_Scalar1);
126        fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
127        fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
128
129        /*
130        It turns out arcTos are not automatically marked as convex and they
131        may in fact be ever so slightly concave.
132        fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
133                                                  50 * SK_Scalar1,
134                                                  100 * SK_Scalar1),
135                                 25 * SK_Scalar1,  130 * SK_Scalar1, false);
136        */
137        // cubics
138        fPaths.push_back().cubicTo( 1 * SK_Scalar1,  1 * SK_Scalar1,
139                                   10 * SK_Scalar1,  90 * SK_Scalar1,
140                                    0 * SK_Scalar1, 100 * SK_Scalar1);
141        fPaths.push_back().cubicTo(100 * SK_Scalar1,  50 * SK_Scalar1,
142                                    20 * SK_Scalar1, 100 * SK_Scalar1,
143                                     0 * SK_Scalar1,   0 * SK_Scalar1);
144
145        // path that has a cubic with a repeated first control point and
146        // a repeated last control point.
147        fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
148        fPaths.back().cubicTo(10 * SK_Scalar1, 10 * SK_Scalar1,
149                              10 * SK_Scalar1, 0,
150                              20 * SK_Scalar1, 0);
151        fPaths.back().lineTo(40 * SK_Scalar1, 0);
152        fPaths.back().cubicTo(40 * SK_Scalar1, 0,
153                              50 * SK_Scalar1, 0,
154                              50 * SK_Scalar1, 10 * SK_Scalar1);
155
156        // path that has two cubics with repeated middle control points.
157        fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
158        fPaths.back().cubicTo(10 * SK_Scalar1, 0,
159                              10 * SK_Scalar1, 0,
160                              20 * SK_Scalar1, 0);
161        fPaths.back().lineTo(40 * SK_Scalar1, 0);
162        fPaths.back().cubicTo(50 * SK_Scalar1, 0,
163                              50 * SK_Scalar1, 0,
164                              50 * SK_Scalar1, 10 * SK_Scalar1);
165
166        // triangle where one edge is a degenerate quad
167        fPaths.push_back().moveTo(SkFloatToScalar(8.59375f), 45 * SK_Scalar1);
168        fPaths.back().quadTo(SkFloatToScalar(16.9921875f),   45 * SK_Scalar1,
169                             SkFloatToScalar(31.25f),        45 * SK_Scalar1);
170        fPaths.back().lineTo(100 * SK_Scalar1,              100 * SK_Scalar1);
171        fPaths.back().lineTo(SkFloatToScalar(8.59375f),      45 * SK_Scalar1);
172
173        // point degenerate
174        fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
175        fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
176
177        fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
178        fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
179                             50 * SK_Scalar1, 50 * SK_Scalar1);
180        fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
181        fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
182                              50 * SK_Scalar1, 50 * SK_Scalar1,
183                              50 * SK_Scalar1, 50 * SK_Scalar1);
184
185        // moveTo only paths
186        fPaths.push_back().moveTo(0, 0);
187        fPaths.back().moveTo(0, 0);
188        fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
189        fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
190        fPaths.back().moveTo(10 * SK_Scalar1, 10 * SK_Scalar1);
191
192        fPaths.push_back().moveTo(0, 0);
193        fPaths.back().moveTo(0, 0);
194
195        // line degenerate
196        fPaths.push_back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
197        fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1, 0, 0);
198        fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1,
199                                  50 * SK_Scalar1, 50 * SK_Scalar1);
200        fPaths.push_back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
201                                  100 * SK_Scalar1, 100 * SK_Scalar1);
202        fPaths.push_back().cubicTo(0, 0,
203                                   0, 0,
204                                   100 * SK_Scalar1, 100 * SK_Scalar1);
205
206        // small circle. This is listed last so that it has device coords far
207        // from the origin (small area relative to x,y values).
208        fPaths.push_back().addCircle(0, 0, SkFloatToScalar(0.8f));
209    }
210
211    virtual void onDraw(SkCanvas* canvas) {
212        this->makePaths();
213
214    SkPaint paint;
215    paint.setAntiAlias(true);
216    SkRandom rand;
217    canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
218    for (int i = 0; i < fPaths.count(); ++i) {
219        canvas->save();
220        // position the path, and make it at off-integer coords.
221        canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 4,
222                          SK_Scalar1 * 200 * (i / 5) + 3 * SK_Scalar1 / 4);
223        SkColor color = rand.nextU();
224        color |= 0xff000000;
225        paint.setColor(color);
226        SkASSERT(fPaths[i].isConvex());
227        canvas->drawPath(fPaths[i], paint);
228        canvas->restore();
229    }
230    }
231
232private:
233    typedef GM INHERITED;
234    SkTArray<SkPath> fPaths;
235};
236
237//////////////////////////////////////////////////////////////////////////////
238
239static GM* MyFactory(void*) { return new ConvexPathsGM; }
240static GMRegistry reg(MyFactory);
241
242}
243
244