blob: a354bd4cef3489c9419b3682bb790cb261bda75f [file] [log] [blame]
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +00001
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
reed@google.comd42e3f62012-03-30 20:04:21 +000012class SkOnce : SkNoncopyable {
13public:
14 SkOnce() { fDidOnce = false; }
rmistry@google.comd6176b02012-08-23 18:14:13 +000015
reed@google.comd42e3f62012-03-30 20:04:21 +000016 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
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000027namespace skiagm {
28
29class ConvexPathsGM : public GM {
reed@google.comd42e3f62012-03-30 20:04:21 +000030 SkOnce fOnce;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000031public:
32 ConvexPathsGM() {
bsalomon@google.com72b55be2012-01-26 20:33:19 +000033 this->setBGColor(0xFF000000);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000034 }
35
36protected:
37 virtual SkString onShortName() {
38 return SkString("convexpaths");
39 }
40
41
42 virtual SkISize onISize() {
bsalomon@google.com54ad8512012-08-02 14:55:45 +000043 return make_isize(1200, 1100);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000044 }
45
46 void makePaths() {
reed@google.comd42e3f62012-03-30 20:04:21 +000047 if (fOnce.alreadyDone()) {
48 return;
49 }
50 fOnce.accomplished();
bsalomon@google.com278dc692012-02-15 16:52:51 +000051 // CW
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 // CCW
58 fPaths.push_back().moveTo(0, 0);
59 fPaths.back().lineTo(0, 100 * SK_Scalar1);
60 fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
61 0, 0);
62
63 // CW
64 fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
65 fPaths.back().quadTo(50 * SK_Scalar1, 0,
66 100 * SK_Scalar1, 50 * SK_Scalar1);
67 fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
68 0, 50 * SK_Scalar1);
69
70 // CCW
71 fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
72 fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
73 100 * SK_Scalar1, 50 * SK_Scalar1);
74 fPaths.back().quadTo(50 * SK_Scalar1, 0,
75 0, 50 * SK_Scalar1);
76
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000077 fPaths.push_back().addRect(0, 0,
78 100 * SK_Scalar1, 100 * SK_Scalar1,
79 SkPath::kCW_Direction);
80
81 fPaths.push_back().addRect(0, 0,
82 100 * SK_Scalar1, 100 * SK_Scalar1,
83 SkPath::kCCW_Direction);
84
85 fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
86 50 * SK_Scalar1, SkPath::kCW_Direction);
87
88 fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
89 40 * SK_Scalar1, SkPath::kCCW_Direction);
90
91 fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
92 50 * SK_Scalar1,
93 100 * SK_Scalar1),
94 SkPath::kCW_Direction);
95
96 fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
97 100 * SK_Scalar1,
98 50 * SK_Scalar1),
99 SkPath::kCCW_Direction);
100
101 fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
102 100 * SK_Scalar1,
103 5 * SK_Scalar1),
104 SkPath::kCCW_Direction);
105
106 fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
107 SK_Scalar1,
108 100 * SK_Scalar1),
109 SkPath::kCCW_Direction);
110
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000111 fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
112 SK_Scalar1 * 100,
113 SK_Scalar1 * 100),
114 40 * SK_Scalar1, 20 * SK_Scalar1,
115 SkPath::kCW_Direction);
116
117 fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
118 SK_Scalar1 * 100,
119 SK_Scalar1 * 100),
120 20 * SK_Scalar1, 40 * SK_Scalar1,
121 SkPath::kCCW_Direction);
bsalomon@google.com72b55be2012-01-26 20:33:19 +0000122
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000123 // large number of points
124 enum {
125 kLength = 100,
126 kPtsPerSide = (1 << 12),
127 };
128 fPaths.push_back().moveTo(0, 0);
129 for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo.
130 fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0);
131 }
132 for (int i = 0; i < kPtsPerSide; ++i) {
133 fPaths.back().lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide);
134 }
135 for (int i = kPtsPerSide; i > 0; --i) {
136 fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength);
137 }
138 for (int i = kPtsPerSide; i > 0; --i) {
139 fPaths.back().lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide);
140 }
141
bsalomon@google.com72b55be2012-01-26 20:33:19 +0000142 // shallow diagonals
143 fPaths.push_back().lineTo(100 * SK_Scalar1, SK_Scalar1);
144 fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
145 fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000146
bsalomon@google.com54ad8512012-08-02 14:55:45 +0000147 //It turns out arcTos are not automatically marked as convex and they
148 //may in fact be ever so slightly concave.
149 //fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
150 // 50 * SK_Scalar1,
151 // 100 * SK_Scalar1),
152 // 25 * SK_Scalar1, 130 * SK_Scalar1, false);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000153
bsalomon@google.com72b55be2012-01-26 20:33:19 +0000154 // cubics
155 fPaths.push_back().cubicTo( 1 * SK_Scalar1, 1 * SK_Scalar1,
156 10 * SK_Scalar1, 90 * SK_Scalar1,
157 0 * SK_Scalar1, 100 * SK_Scalar1);
158 fPaths.push_back().cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
159 20 * SK_Scalar1, 100 * SK_Scalar1,
160 0 * SK_Scalar1, 0 * SK_Scalar1);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000161
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000162 // path that has a cubic with a repeated first control point and
163 // a repeated last control point.
164 fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
165 fPaths.back().cubicTo(10 * SK_Scalar1, 10 * SK_Scalar1,
166 10 * SK_Scalar1, 0,
167 20 * SK_Scalar1, 0);
168 fPaths.back().lineTo(40 * SK_Scalar1, 0);
169 fPaths.back().cubicTo(40 * SK_Scalar1, 0,
170 50 * SK_Scalar1, 0,
171 50 * SK_Scalar1, 10 * SK_Scalar1);
172
173 // path that has two cubics with repeated middle control points.
174 fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
175 fPaths.back().cubicTo(10 * SK_Scalar1, 0,
176 10 * SK_Scalar1, 0,
177 20 * SK_Scalar1, 0);
178 fPaths.back().lineTo(40 * SK_Scalar1, 0);
179 fPaths.back().cubicTo(50 * SK_Scalar1, 0,
180 50 * SK_Scalar1, 0,
181 50 * SK_Scalar1, 10 * SK_Scalar1);
182
bsalomon@google.com54ad8512012-08-02 14:55:45 +0000183 // cubic where last three points are almost a line
184 fPaths.push_back().moveTo(0, 228 * SK_Scalar1 / 8);
185 fPaths.back().cubicTo(628 * SK_Scalar1 / 8, 82 * SK_Scalar1 / 8,
186 1255 * SK_Scalar1 / 8, 141 * SK_Scalar1 / 8,
187 1883 * SK_Scalar1 / 8, 202 * SK_Scalar1 / 8);
188
189 // flat cubic where the at end point tangents both point outward.
190 fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
191 fPaths.back().cubicTo(0, SK_Scalar1,
192 30 * SK_Scalar1, SK_Scalar1,
193 20 * SK_Scalar1, 0);
194
195 // flat cubic where initial tangent is in, end tangent out
196 fPaths.push_back().moveTo(0, 0 * SK_Scalar1);
197 fPaths.back().cubicTo(10 * SK_Scalar1, SK_Scalar1,
198 30 * SK_Scalar1, SK_Scalar1,
199 20 * SK_Scalar1, 0);
200
201 // flat cubic where initial tangent is out, end tangent in
202 fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
203 fPaths.back().cubicTo(0, SK_Scalar1,
204 20 * SK_Scalar1, SK_Scalar1,
205 30 * SK_Scalar1, 0);
206
bsalomon@google.comdc3c7802012-01-31 20:46:32 +0000207 // triangle where one edge is a degenerate quad
208 fPaths.push_back().moveTo(SkFloatToScalar(8.59375f), 45 * SK_Scalar1);
209 fPaths.back().quadTo(SkFloatToScalar(16.9921875f), 45 * SK_Scalar1,
210 SkFloatToScalar(31.25f), 45 * SK_Scalar1);
211 fPaths.back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
212 fPaths.back().lineTo(SkFloatToScalar(8.59375f), 45 * SK_Scalar1);
213
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000214 // point degenerate
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000215 fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
216 fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000217
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000218 fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
219 fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
220 50 * SK_Scalar1, 50 * SK_Scalar1);
221 fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
222 fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
223 50 * SK_Scalar1, 50 * SK_Scalar1,
224 50 * SK_Scalar1, 50 * SK_Scalar1);
bsalomon@google.comdc3c7802012-01-31 20:46:32 +0000225
bsalomon@google.com9732f622012-01-31 15:19:21 +0000226 // moveTo only paths
227 fPaths.push_back().moveTo(0, 0);
228 fPaths.back().moveTo(0, 0);
229 fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
230 fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
231 fPaths.back().moveTo(10 * SK_Scalar1, 10 * SK_Scalar1);
232
233 fPaths.push_back().moveTo(0, 0);
234 fPaths.back().moveTo(0, 0);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000235
236 // line degenerate
237 fPaths.push_back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
238 fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1, 0, 0);
239 fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1,
240 50 * SK_Scalar1, 50 * SK_Scalar1);
241 fPaths.push_back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
242 100 * SK_Scalar1, 100 * SK_Scalar1);
243 fPaths.push_back().cubicTo(0, 0,
244 0, 0,
245 100 * SK_Scalar1, 100 * SK_Scalar1);
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +0000246
247 // small circle. This is listed last so that it has device coords far
248 // from the origin (small area relative to x,y values).
249 fPaths.push_back().addCircle(0, 0, SkFloatToScalar(0.8f));
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000250 }
251
252 virtual void onDraw(SkCanvas* canvas) {
reed@google.comd42e3f62012-03-30 20:04:21 +0000253 this->makePaths();
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000254
255 SkPaint paint;
256 paint.setAntiAlias(true);
257 SkRandom rand;
258 canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
bsalomon@google.com72b55be2012-01-26 20:33:19 +0000259 for (int i = 0; i < fPaths.count(); ++i) {
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000260 canvas->save();
261 // position the path, and make it at off-integer coords.
262 canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 4,
263 SK_Scalar1 * 200 * (i / 5) + 3 * SK_Scalar1 / 4);
264 SkColor color = rand.nextU();
265 color |= 0xff000000;
266 paint.setColor(color);
267 SkASSERT(fPaths[i].isConvex());
268 canvas->drawPath(fPaths[i], paint);
269 canvas->restore();
270 }
271 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000272
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000273private:
274 typedef GM INHERITED;
275 SkTArray<SkPath> fPaths;
276};
277
278//////////////////////////////////////////////////////////////////////////////
279
280static GM* MyFactory(void*) { return new ConvexPathsGM; }
281static GMRegistry reg(MyFactory);
282
283}