blob: 9de66ea9ea2c23be51ae227f82ba0a889a73863f [file] [log] [blame]
schenney@chromium.org4da06ab2011-12-20 15:14:18 +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 */
7#include "gm.h"
Mike Klein33d20552017-03-22 13:47:51 -04008#include "sk_tool_utils.h"
schenney@chromium.org4da06ab2011-12-20 15:14:18 +00009#include "SkCanvas.h"
10#include "SkPaint.h"
bungemand3ebb482015-08-05 13:57:49 -070011#include "SkPath.h"
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000012#include "SkRandom.h"
13
14namespace skiagm {
15
16class DegenerateSegmentsGM : public GM {
17public:
18 DegenerateSegmentsGM() {}
19
20protected:
21 struct PathAndName {
22 SkPath fPath;
23 const char* fName1;
24 const char* fName2;
25 };
26
27 SkString onShortName() {
28 return SkString("degeneratesegments");
29 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000030
tfarinaf5393182014-06-09 23:59:03 -070031 SkISize onISize() { return SkISize::Make(896, 930); }
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000032
33 typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
rmistry@google.comd6176b02012-08-23 18:14:13 +000034
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000035 // We need to use explicit commands here, instead of addPath, because we
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000036 // do not want the moveTo that is added at the beginning of a path to
37 // appear in the appended path.
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000038 static SkPoint AddMove(SkPath& path, SkPoint& startPt) {
39 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
40 path.moveTo(moveToPt);
41 return moveToPt;
42 }
43
44 static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) {
45 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
46 path.moveTo(moveToPt);
47 path.close();
48 return moveToPt;
49 }
50
51 static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
52 path.lineTo(startPt);
53 return startPt;
54 }
55
56 static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) {
57 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
58 path.moveTo(moveToPt);
59 path.lineTo(moveToPt);
60 return moveToPt;
61 }
62
63 static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) {
64 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
65 path.moveTo(moveToPt);
66 path.lineTo(moveToPt);
67 path.close();
68 return moveToPt;
69 }
70
71 static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
72 path.quadTo(startPt, startPt);
73 return startPt;
74 }
75
76 static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) {
77 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
78 path.moveTo(moveToPt);
79 path.quadTo(moveToPt, moveToPt);
80 return moveToPt;
81 }
82
83 static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) {
84 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
85 path.moveTo(moveToPt);
86 path.quadTo(moveToPt, moveToPt);
87 path.close();
88 return moveToPt;
89 }
90
91 static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
92 path.cubicTo(startPt, startPt, startPt);
93 return startPt;
94 }
95
96 static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) {
97 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
98 path.moveTo(moveToPt);
99 path.cubicTo(moveToPt, moveToPt, moveToPt);
100 return moveToPt;
101 }
102
103 static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) {
104 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
105 path.moveTo(moveToPt);
106 path.cubicTo(moveToPt, moveToPt, moveToPt);
107 path.close();
108 return moveToPt;
109 }
110
111 static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
112 path.close();
113 return startPt;
114 }
115
116 static SkPoint AddLine(SkPath& path, SkPoint& startPt) {
117 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
118 path.lineTo(endPt);
119 return endPt;
120 }
121
122 static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) {
123 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
124 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
125 path.moveTo(moveToPt);
126 path.lineTo(endPt);
127 return endPt;
128 }
129
130 static SkPoint AddMoveLineClose(SkPath& path, SkPoint& startPt) {
131 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
132 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
133 path.moveTo(moveToPt);
134 path.lineTo(endPt);
135 path.close();
136 return endPt;
137 }
138
139 static SkPoint AddQuad(SkPath& path, SkPoint& startPt) {
140 SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
141 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
142 path.quadTo(midPt, endPt);
143 return endPt;
144 }
145
146 static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) {
147 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
148 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
149 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
150 path.moveTo(moveToPt);
151 path.quadTo(midPt, endPt);
152 return endPt;
153 }
154
155 static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) {
156 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
157 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
158 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
159 path.moveTo(moveToPt);
160 path.quadTo(midPt, endPt);
161 path.close();
162 return endPt;
163 }
164
165 static SkPoint AddCubic(SkPath& path, SkPoint& startPt) {
166 SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
167 SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
168 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
169 path.cubicTo(t1Pt, t2Pt, endPt);
170 return endPt;
171 }
172
173 static SkPoint AddMoveCubic(SkPath& path, SkPoint& startPt) {
174 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
175 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
176 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
177 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
178 path.moveTo(moveToPt);
179 path.cubicTo(t1Pt, t2Pt, endPt);
180 return endPt;
181 }
182
183 static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) {
184 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
185 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
186 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
187 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
188 path.moveTo(moveToPt);
189 path.cubicTo(t1Pt, t2Pt, endPt);
190 path.close();
191 return endPt;
192 }
193
194 void drawPath(SkPath& path, SkCanvas* canvas, SkColor color,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000195 const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000196 SkPaint::Style style, SkPath::FillType fill,
197 SkScalar strokeWidth) {
198 path.setFillType(fill);
199 SkPaint paint;
200 paint.setStrokeCap(cap);
201 paint.setStrokeWidth(strokeWidth);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000202 paint.setStrokeJoin(join);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000203 paint.setColor(color);
204 paint.setStyle(style);
205 canvas->save();
206 canvas->clipRect(clip);
207 canvas->drawPath(path, paint);
208 canvas->restore();
209 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000210
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000211 virtual void onDraw(SkCanvas* canvas) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700212 constexpr AddSegmentFunc gSegmentFunctions[] = {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000213 AddMove,
214 AddMoveClose,
215 AddDegenLine,
216 AddMoveDegenLine,
217 AddMoveDegenLineClose,
218 AddDegenQuad,
219 AddMoveDegenQuad,
220 AddMoveDegenQuadClose,
221 AddDegenCubic,
222 AddMoveDegenCubic,
223 AddMoveDegenCubicClose,
224 AddClose,
225 AddLine,
226 AddMoveLine,
227 AddMoveLineClose,
228 AddQuad,
229 AddMoveQuad,
230 AddMoveQuadClose,
231 AddCubic,
232 AddMoveCubic,
233 AddMoveCubicClose
234 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700235 const char* gSegmentNames[] = {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000236 "Move",
237 "MoveClose",
238 "DegenLine",
239 "MoveDegenLine",
240 "MoveDegenLineClose",
241 "DegenQuad",
242 "MoveDegenQuad",
243 "MoveDegenQuadClose",
244 "DegenCubic",
245 "MoveDegenCubic",
246 "MoveDegenCubicClose",
247 "Close",
248 "Line",
249 "MoveLine",
250 "MoveLineClose",
251 "Quad",
252 "MoveQuad",
253 "MoveQuadClose",
254 "Cubic",
255 "MoveCubic",
256 "MoveCubicClose"
257 };
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000258
259 struct FillAndName {
260 SkPath::FillType fFill;
261 const char* fName;
262 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700263 constexpr FillAndName gFills[] = {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000264 {SkPath::kWinding_FillType, "Winding"},
265 {SkPath::kEvenOdd_FillType, "Even / Odd"},
266 {SkPath::kInverseWinding_FillType, "Inverse Winding"},
267 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}
268 };
269 struct StyleAndName {
270 SkPaint::Style fStyle;
271 const char* fName;
272 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700273 constexpr StyleAndName gStyles[] = {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000274 {SkPaint::kFill_Style, "Fill"},
275 {SkPaint::kStroke_Style, "Stroke 10"},
276 {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
277 };
278 struct CapAndName {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000279 SkPaint::Cap fCap;
280 SkPaint::Join fJoin;
281 const char* fName;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000282 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700283 constexpr CapAndName gCaps[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000284 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
285 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
286 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000287 };
288
289 SkPaint titlePaint;
290 titlePaint.setColor(SK_ColorBLACK);
291 titlePaint.setAntiAlias(true);
caryclark1818acb2015-07-24 12:09:25 -0700292 sk_tool_utils::set_portable_typeface(&titlePaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000293 titlePaint.setTextSize(15 * SK_Scalar1);
294 const char title[] = "Random Paths Drawn Into Rectangle Clips With "
295 "Indicated Style, Fill and Linecaps, "
296 "with Stroke width 6";
Cary Clark2a475ea2017-04-28 15:35:12 -0400297 canvas->drawString(title,
298 20 * SK_Scalar1,
299 20 * SK_Scalar1,
300 titlePaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000301
scroggof9d61012014-12-15 12:54:51 -0800302 SkRandom rand;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000303 SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
304 canvas->save();
305 canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
306 canvas->save();
307 unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
308 unsigned numCaps = SK_ARRAY_COUNT(gCaps);
309 unsigned numStyles = SK_ARRAY_COUNT(gStyles);
310 unsigned numFills = SK_ARRAY_COUNT(gFills);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000311 for (size_t row = 0; row < 6; ++row) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000312 if (0 < row) {
313 canvas->translate(0, rect.height() + 100*SK_Scalar1);
314 }
315 canvas->save();
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000316 for (size_t column = 0; column < 4; ++column) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000317 if (0 < column) {
318 canvas->translate(rect.width() + 4*SK_Scalar1, 0);
319 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000320
caryclarkdfcb7ab2015-07-17 09:39:16 -0700321 SkColor color = sk_tool_utils::color_to_565(0xff007000);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000322 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
323 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
324 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
325 SkPath path;
326 unsigned s1 = (rand.nextU() >> 16) % numSegments;
327 unsigned s2 = (rand.nextU() >> 16) % numSegments;
328 unsigned s3 = (rand.nextU() >> 16) % numSegments;
329 unsigned s4 = (rand.nextU() >> 16) % numSegments;
330 unsigned s5 = (rand.nextU() >> 16) % numSegments;
331 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
332 pt = gSegmentFunctions[s1](path, pt);
333 pt = gSegmentFunctions[s2](path, pt);
334 pt = gSegmentFunctions[s3](path, pt);
335 pt = gSegmentFunctions[s4](path, pt);
336 pt = gSegmentFunctions[s5](path, pt);
337
338 this->drawPath(path, canvas, color, rect,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000339 cap.fCap, cap.fJoin, style.fStyle,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000340 fill.fFill, SK_Scalar1*6);
341
342 SkPaint rectPaint;
343 rectPaint.setColor(SK_ColorBLACK);
344 rectPaint.setStyle(SkPaint::kStroke_Style);
345 rectPaint.setStrokeWidth(-1);
346 rectPaint.setAntiAlias(true);
347 canvas->drawRect(rect, rectPaint);
348
349 SkPaint labelPaint;
350 labelPaint.setColor(color);
351 labelPaint.setAntiAlias(true);
caryclark1818acb2015-07-24 12:09:25 -0700352 sk_tool_utils::set_portable_typeface(&labelPaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000353 labelPaint.setTextSize(10 * SK_Scalar1);
Cary Clark2a475ea2017-04-28 15:35:12 -0400354 canvas->drawString(style.fName,
355 0, rect.height() + 12 * SK_Scalar1,
356 labelPaint);
357 canvas->drawString(fill.fName,
358 0, rect.height() + 24 * SK_Scalar1,
359 labelPaint);
360 canvas->drawString(cap.fName,
361 0, rect.height() + 36 * SK_Scalar1,
362 labelPaint);
363 canvas->drawString(gSegmentNames[s1],
364 0, rect.height() + 48 * SK_Scalar1,
365 labelPaint);
366 canvas->drawString(gSegmentNames[s2],
367 0, rect.height() + 60 * SK_Scalar1,
368 labelPaint);
369 canvas->drawString(gSegmentNames[s3],
370 0, rect.height() + 72 * SK_Scalar1,
371 labelPaint);
372 canvas->drawString(gSegmentNames[s4],
373 0, rect.height() + 84 * SK_Scalar1,
374 labelPaint);
375 canvas->drawString(gSegmentNames[s5],
376 0, rect.height() + 96 * SK_Scalar1,
377 labelPaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000378 }
379 canvas->restore();
380 }
381 canvas->restore();
382 canvas->restore();
383 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000384
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000385private:
386 typedef GM INHERITED;
387};
388
389//////////////////////////////////////////////////////////////////////////////
390
391static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
392static GMRegistry reg(MyFactory);
393
394}