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