blob: 0fa0e34e35e1d671c04986e46ad44864e5a96413 [file] [log] [blame]
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +00001/*
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 */
Ben Wagner7fde8e12019-05-01 17:28:53 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#include "include/core/SkCanvas.h"
10#include "include/core/SkColor.h"
11#include "include/core/SkMatrix.h"
12#include "include/core/SkPaint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040014#include "include/core/SkRect.h"
15#include "include/core/SkScalar.h"
16#include "include/core/SkSize.h"
17#include "include/core/SkString.h"
18#include "include/core/SkTypes.h"
19#include "include/private/SkNoncopyable.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "include/private/SkTArray.h"
21#include "include/utils/SkRandom.h"
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000022
Hal Canarybd865e22019-07-18 11:51:19 -040023namespace {
24
commit-bot@chromium.org2ab1ba02014-01-17 17:55:02 +000025class SkDoOnce : SkNoncopyable {
reed@google.comd42e3f62012-03-30 20:04:21 +000026public:
commit-bot@chromium.org2ab1ba02014-01-17 17:55:02 +000027 SkDoOnce() { fDidOnce = false; }
rmistry@google.comd6176b02012-08-23 18:14:13 +000028
reed@google.comd42e3f62012-03-30 20:04:21 +000029 bool needToDo() const { return !fDidOnce; }
30 bool alreadyDone() const { return fDidOnce; }
31 void accomplished() {
32 SkASSERT(!fDidOnce);
33 fDidOnce = true;
34 }
35
36private:
37 bool fDidOnce;
38};
39
Hal Canarybd865e22019-07-18 11:51:19 -040040class ConvexPathsGM : public skiagm::GM {
commit-bot@chromium.org2ab1ba02014-01-17 17:55:02 +000041 SkDoOnce fOnce;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000042
Hal Canarybd865e22019-07-18 11:51:19 -040043 void onOnceBeforeDraw() override { this->setBGColor(0xFF000000); }
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000044
Hal Canarybd865e22019-07-18 11:51:19 -040045 SkString onShortName() override { return SkString("convexpaths"); }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000046
47
Hal Canarybd865e22019-07-18 11:51:19 -040048 SkISize onISize() override { return {1200, 1100}; }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000049
50 void makePaths() {
reed@google.comd42e3f62012-03-30 20:04:21 +000051 if (fOnce.alreadyDone()) {
52 return;
53 }
54 fOnce.accomplished();
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +000055
bsalomon@google.com278dc692012-02-15 16:52:51 +000056 fPaths.push_back().moveTo(0, 0);
57 fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
58 0, 100 * SK_Scalar1);
59 fPaths.back().lineTo(0, 0);
60
bsalomon@google.com278dc692012-02-15 16:52:51 +000061 fPaths.push_back().moveTo(0, 50 * SK_Scalar1);
62 fPaths.back().quadTo(50 * SK_Scalar1, 0,
63 100 * SK_Scalar1, 50 * SK_Scalar1);
64 fPaths.back().quadTo(50 * SK_Scalar1, 100 * SK_Scalar1,
65 0, 50 * SK_Scalar1);
66
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000067 fPaths.push_back().addRect(0, 0,
68 100 * SK_Scalar1, 100 * SK_Scalar1,
Mike Reed30bc5272019-11-22 18:34:02 +000069 SkPathDirection::kCW);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000070
71 fPaths.push_back().addRect(0, 0,
72 100 * SK_Scalar1, 100 * SK_Scalar1,
Mike Reed30bc5272019-11-22 18:34:02 +000073 SkPathDirection::kCCW);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000074
75 fPaths.push_back().addCircle(50 * SK_Scalar1, 50 * SK_Scalar1,
Mike Reed30bc5272019-11-22 18:34:02 +000076 50 * SK_Scalar1, SkPathDirection::kCW);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000077
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000078
79 fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
80 50 * SK_Scalar1,
81 100 * SK_Scalar1),
Mike Reed30bc5272019-11-22 18:34:02 +000082 SkPathDirection::kCW);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000083
84 fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
85 100 * SK_Scalar1,
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000086 5 * SK_Scalar1),
Mike Reed30bc5272019-11-22 18:34:02 +000087 SkPathDirection::kCCW);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000088
89 fPaths.push_back().addOval(SkRect::MakeXYWH(0, 0,
90 SK_Scalar1,
91 100 * SK_Scalar1),
Mike Reed30bc5272019-11-22 18:34:02 +000092 SkPathDirection::kCCW);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000093
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000094 fPaths.push_back().addRoundRect(SkRect::MakeXYWH(0, 0,
95 SK_Scalar1 * 100,
96 SK_Scalar1 * 100),
97 40 * SK_Scalar1, 20 * SK_Scalar1,
Mike Reed30bc5272019-11-22 18:34:02 +000098 SkPathDirection::kCW);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000099
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000100 // large number of points
101 enum {
102 kLength = 100,
103 kPtsPerSide = (1 << 12),
104 };
105 fPaths.push_back().moveTo(0, 0);
106 for (int i = 1; i < kPtsPerSide; ++i) { // skip the first point due to moveTo.
107 fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, 0);
108 }
109 for (int i = 0; i < kPtsPerSide; ++i) {
110 fPaths.back().lineTo(kLength, kLength * SkIntToScalar(i) / kPtsPerSide);
111 }
112 for (int i = kPtsPerSide; i > 0; --i) {
113 fPaths.back().lineTo(kLength * SkIntToScalar(i) / kPtsPerSide, kLength);
114 }
115 for (int i = kPtsPerSide; i > 0; --i) {
116 fPaths.back().lineTo(0, kLength * SkIntToScalar(i) / kPtsPerSide);
117 }
118
bsalomon@google.com72b55be2012-01-26 20:33:19 +0000119 // shallow diagonals
120 fPaths.push_back().lineTo(100 * SK_Scalar1, SK_Scalar1);
121 fPaths.back().lineTo(98 * SK_Scalar1, 100 * SK_Scalar1);
122 fPaths.back().lineTo(3 * SK_Scalar1, 96 * SK_Scalar1);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000123
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000124 fPaths.push_back().arcTo(SkRect::MakeXYWH(0, 0,
125 50 * SK_Scalar1,
126 100 * SK_Scalar1),
127 25 * SK_Scalar1, 130 * SK_Scalar1, false);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000128
bsalomon@google.com72b55be2012-01-26 20:33:19 +0000129 // cubics
130 fPaths.push_back().cubicTo( 1 * SK_Scalar1, 1 * SK_Scalar1,
131 10 * SK_Scalar1, 90 * SK_Scalar1,
132 0 * SK_Scalar1, 100 * SK_Scalar1);
133 fPaths.push_back().cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
134 20 * SK_Scalar1, 100 * SK_Scalar1,
135 0 * SK_Scalar1, 0 * SK_Scalar1);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000136
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000137 // path that has a cubic with a repeated first control point and
138 // a repeated last control point.
139 fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
140 fPaths.back().cubicTo(10 * SK_Scalar1, 10 * SK_Scalar1,
141 10 * SK_Scalar1, 0,
142 20 * SK_Scalar1, 0);
143 fPaths.back().lineTo(40 * SK_Scalar1, 0);
144 fPaths.back().cubicTo(40 * SK_Scalar1, 0,
145 50 * SK_Scalar1, 0,
146 50 * SK_Scalar1, 10 * SK_Scalar1);
147
148 // path that has two cubics with repeated middle control points.
149 fPaths.push_back().moveTo(SK_Scalar1 * 10, SK_Scalar1 * 10);
150 fPaths.back().cubicTo(10 * SK_Scalar1, 0,
151 10 * SK_Scalar1, 0,
152 20 * SK_Scalar1, 0);
153 fPaths.back().lineTo(40 * SK_Scalar1, 0);
154 fPaths.back().cubicTo(50 * SK_Scalar1, 0,
155 50 * SK_Scalar1, 0,
156 50 * SK_Scalar1, 10 * SK_Scalar1);
157
bsalomon@google.com54ad8512012-08-02 14:55:45 +0000158 // cubic where last three points are almost a line
159 fPaths.push_back().moveTo(0, 228 * SK_Scalar1 / 8);
160 fPaths.back().cubicTo(628 * SK_Scalar1 / 8, 82 * SK_Scalar1 / 8,
161 1255 * SK_Scalar1 / 8, 141 * SK_Scalar1 / 8,
162 1883 * SK_Scalar1 / 8, 202 * SK_Scalar1 / 8);
163
164 // flat cubic where the at end point tangents both point outward.
165 fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
166 fPaths.back().cubicTo(0, SK_Scalar1,
167 30 * SK_Scalar1, SK_Scalar1,
168 20 * SK_Scalar1, 0);
169
170 // flat cubic where initial tangent is in, end tangent out
171 fPaths.push_back().moveTo(0, 0 * SK_Scalar1);
172 fPaths.back().cubicTo(10 * SK_Scalar1, SK_Scalar1,
173 30 * SK_Scalar1, SK_Scalar1,
174 20 * SK_Scalar1, 0);
175
176 // flat cubic where initial tangent is out, end tangent in
177 fPaths.push_back().moveTo(10 * SK_Scalar1, 0);
178 fPaths.back().cubicTo(0, SK_Scalar1,
179 20 * SK_Scalar1, SK_Scalar1,
180 30 * SK_Scalar1, 0);
181
bsalomon@google.comdc3c7802012-01-31 20:46:32 +0000182 // triangle where one edge is a degenerate quad
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000183 fPaths.push_back().moveTo(8.59375f, 45 * SK_Scalar1);
184 fPaths.back().quadTo(16.9921875f, 45 * SK_Scalar1,
185 31.25f, 45 * SK_Scalar1);
bsalomon@google.comdc3c7802012-01-31 20:46:32 +0000186 fPaths.back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000187 fPaths.back().lineTo(8.59375f, 45 * SK_Scalar1);
bsalomon@google.comdc3c7802012-01-31 20:46:32 +0000188
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000189 // triangle where one edge is a quad with a repeated point
190 fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
191 fPaths.back().lineTo(50 * SK_Scalar1, 0);
192 fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1, 50 * SK_Scalar1);
193
194 // triangle where one edge is a cubic with a 2x repeated point
195 fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
196 fPaths.back().lineTo(50 * SK_Scalar1, 0);
197 fPaths.back().cubicTo(50 * SK_Scalar1, 0,
198 50 * SK_Scalar1, 50 * SK_Scalar1,
199 50 * SK_Scalar1, 50 * SK_Scalar1);
200
201 // triangle where one edge is a quad with a nearly repeated point
202 fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
203 fPaths.back().lineTo(50 * SK_Scalar1, 0);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000204 fPaths.back().quadTo(50 * SK_Scalar1, 49.95f,
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000205 50 * SK_Scalar1, 50 * SK_Scalar1);
206
207 // triangle where one edge is a cubic with a 3x nearly repeated point
208 fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
209 fPaths.back().lineTo(50 * SK_Scalar1, 0);
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000210 fPaths.back().cubicTo(50 * SK_Scalar1, 49.95f,
211 50 * SK_Scalar1, 49.97f,
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000212 50 * SK_Scalar1, 50 * SK_Scalar1);
213
214 // triangle where there is a point degenerate cubic at one corner
215 fPaths.push_back().moveTo(0, 25 * SK_Scalar1);
216 fPaths.back().lineTo(50 * SK_Scalar1, 0);
217 fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
218 fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
219 50 * SK_Scalar1, 50 * SK_Scalar1,
220 50 * SK_Scalar1, 50 * SK_Scalar1);
221
222 // point line
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000223 fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
224 fPaths.back().lineTo(50 * SK_Scalar1, 50 * SK_Scalar1);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000225
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000226 // point quad
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000227 fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
228 fPaths.back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
229 50 * SK_Scalar1, 50 * SK_Scalar1);
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000230
231 // point cubic
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000232 fPaths.push_back().moveTo(50 * SK_Scalar1, 50 * SK_Scalar1);
233 fPaths.back().cubicTo(50 * SK_Scalar1, 50 * SK_Scalar1,
234 50 * SK_Scalar1, 50 * SK_Scalar1,
235 50 * SK_Scalar1, 50 * SK_Scalar1);
bsalomon@google.comdc3c7802012-01-31 20:46:32 +0000236
bsalomon@google.com9732f622012-01-31 15:19:21 +0000237 // moveTo only paths
238 fPaths.push_back().moveTo(0, 0);
239 fPaths.back().moveTo(0, 0);
240 fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
241 fPaths.back().moveTo(SK_Scalar1, SK_Scalar1);
242 fPaths.back().moveTo(10 * SK_Scalar1, 10 * SK_Scalar1);
243
244 fPaths.push_back().moveTo(0, 0);
245 fPaths.back().moveTo(0, 0);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000246
247 // line degenerate
248 fPaths.push_back().lineTo(100 * SK_Scalar1, 100 * SK_Scalar1);
249 fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1, 0, 0);
250 fPaths.push_back().quadTo(100 * SK_Scalar1, 100 * SK_Scalar1,
251 50 * SK_Scalar1, 50 * SK_Scalar1);
252 fPaths.push_back().quadTo(50 * SK_Scalar1, 50 * SK_Scalar1,
253 100 * SK_Scalar1, 100 * SK_Scalar1);
254 fPaths.push_back().cubicTo(0, 0,
255 0, 0,
256 100 * SK_Scalar1, 100 * SK_Scalar1);
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +0000257
Brian Salomon73c6c9d2019-03-29 15:41:27 -0400258 // skbug.com/8928
259 fPaths.push_back().moveTo(16.875f, 192.594f);
260 fPaths.back().cubicTo(45.625f, 192.594f, 74.375f, 192.594f, 103.125f, 192.594f);
261 fPaths.back().cubicTo(88.75f, 167.708f, 74.375f, 142.823f, 60, 117.938f);
262 fPaths.back().cubicTo(45.625f, 142.823f, 31.25f, 167.708f, 16.875f, 192.594f);
263 fPaths.back().close();
264 SkMatrix m;
265 m.setAll(0.1f, 0, -1, 0, 0.115207f, -2.64977f, 0, 0, 1);
266 fPaths.back().transform(m);
267
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +0000268 // small circle. This is listed last so that it has device coords far
269 // from the origin (small area relative to x,y values).
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000270 fPaths.push_back().addCircle(0, 0, 1.2f);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000271 }
272
Hal Canarybd865e22019-07-18 11:51:19 -0400273 void onDraw(SkCanvas* canvas) override {
reed@google.comd42e3f62012-03-30 20:04:21 +0000274 this->makePaths();
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000275
Jim Van Verthf9e678d2017-02-15 15:46:52 -0500276 SkPaint paint;
277 paint.setAntiAlias(true);
278 SkRandom rand;
279 canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1);
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000280
Jim Van Verthf9e678d2017-02-15 15:46:52 -0500281 // As we've added more paths this has gotten pretty big. Scale the whole thing down.
282 canvas->scale(2 * SK_Scalar1 / 3, 2 * SK_Scalar1 / 3);
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000283
Jim Van Verthf9e678d2017-02-15 15:46:52 -0500284 for (int i = 0; i < fPaths.count(); ++i) {
285 canvas->save();
286 // position the path, and make it at off-integer coords.
287 canvas->translate(SK_Scalar1 * 200 * (i % 5) + SK_Scalar1 / 10,
288 SK_Scalar1 * 200 * (i / 5) + 9 * SK_Scalar1 / 10);
289 SkColor color = rand.nextU();
290 color |= 0xff000000;
291 paint.setColor(color);
292#if 0 // This hitting on 32bit Linux builds for some paths. Temporarily disabling while it is
293 // debugged.
294 SkASSERT(fPaths[i].isConvex());
bsalomon@google.com44d662b2013-08-15 20:34:45 +0000295#endif
Jim Van Verthf9e678d2017-02-15 15:46:52 -0500296 canvas->drawPath(fPaths[i], paint);
297 canvas->restore();
298 }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000299 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000300
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000301 SkTArray<SkPath> fPaths;
302};
Hal Canarybd865e22019-07-18 11:51:19 -0400303} // namespace
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000304
Hal Canarye964c182019-01-23 10:22:01 -0500305DEF_GM( return new ConvexPathsGM; )