blob: 596da5e19b3031715395a38db65a31d68516698b [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 */
Ben Wagner7fde8e12019-05-01 17:28:53 -04007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040010#include "include/core/SkColor.h"
11#include "include/core/SkFont.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkPaint.h"
13#include "include/core/SkPath.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -040014#include "include/core/SkPoint.h"
15#include "include/core/SkRect.h"
16#include "include/core/SkScalar.h"
17#include "include/core/SkSize.h"
18#include "include/core/SkString.h"
19#include "include/core/SkTypeface.h"
20#include "include/core/SkTypes.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/utils/SkRandom.h"
22#include "tools/ToolUtils.h"
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000023
24namespace skiagm {
25
26class DegenerateSegmentsGM : public GM {
27public:
28 DegenerateSegmentsGM() {}
29
30protected:
31 struct PathAndName {
32 SkPath fPath;
33 const char* fName1;
34 const char* fName2;
35 };
36
37 SkString onShortName() {
38 return SkString("degeneratesegments");
39 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000040
tfarinaf5393182014-06-09 23:59:03 -070041 SkISize onISize() { return SkISize::Make(896, 930); }
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000042
43 typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
rmistry@google.comd6176b02012-08-23 18:14:13 +000044
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000045 // We need to use explicit commands here, instead of addPath, because we
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000046 // do not want the moveTo that is added at the beginning of a path to
47 // appear in the appended path.
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000048 static SkPoint AddMove(SkPath& path, SkPoint& startPt) {
49 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
50 path.moveTo(moveToPt);
51 return moveToPt;
52 }
53
54 static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) {
55 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
56 path.moveTo(moveToPt);
57 path.close();
58 return moveToPt;
59 }
60
61 static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
62 path.lineTo(startPt);
63 return startPt;
64 }
65
66 static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) {
67 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
68 path.moveTo(moveToPt);
69 path.lineTo(moveToPt);
70 return moveToPt;
71 }
72
73 static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) {
74 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
75 path.moveTo(moveToPt);
76 path.lineTo(moveToPt);
77 path.close();
78 return moveToPt;
79 }
80
81 static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
82 path.quadTo(startPt, startPt);
83 return startPt;
84 }
85
86 static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) {
87 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
88 path.moveTo(moveToPt);
89 path.quadTo(moveToPt, moveToPt);
90 return moveToPt;
91 }
92
93 static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) {
94 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
95 path.moveTo(moveToPt);
96 path.quadTo(moveToPt, moveToPt);
97 path.close();
98 return moveToPt;
99 }
100
101 static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
102 path.cubicTo(startPt, startPt, startPt);
103 return startPt;
104 }
105
106 static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) {
107 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
108 path.moveTo(moveToPt);
109 path.cubicTo(moveToPt, moveToPt, moveToPt);
110 return moveToPt;
111 }
112
113 static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) {
114 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
115 path.moveTo(moveToPt);
116 path.cubicTo(moveToPt, moveToPt, moveToPt);
117 path.close();
118 return moveToPt;
119 }
120
121 static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
122 path.close();
123 return startPt;
124 }
125
126 static SkPoint AddLine(SkPath& path, SkPoint& startPt) {
127 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
128 path.lineTo(endPt);
129 return endPt;
130 }
131
132 static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) {
133 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
134 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
135 path.moveTo(moveToPt);
136 path.lineTo(endPt);
137 return endPt;
138 }
139
140 static SkPoint AddMoveLineClose(SkPath& path, SkPoint& startPt) {
141 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
142 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
143 path.moveTo(moveToPt);
144 path.lineTo(endPt);
145 path.close();
146 return endPt;
147 }
148
149 static SkPoint AddQuad(SkPath& path, SkPoint& startPt) {
150 SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
151 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
152 path.quadTo(midPt, endPt);
153 return endPt;
154 }
155
156 static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) {
157 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
158 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
159 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
160 path.moveTo(moveToPt);
161 path.quadTo(midPt, endPt);
162 return endPt;
163 }
164
165 static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) {
166 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
167 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
168 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
169 path.moveTo(moveToPt);
170 path.quadTo(midPt, endPt);
171 path.close();
172 return endPt;
173 }
174
175 static SkPoint AddCubic(SkPath& path, SkPoint& startPt) {
176 SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
177 SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
178 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
179 path.cubicTo(t1Pt, t2Pt, endPt);
180 return endPt;
181 }
182
183 static SkPoint AddMoveCubic(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 return endPt;
191 }
192
193 static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) {
194 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
195 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
196 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
197 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
198 path.moveTo(moveToPt);
199 path.cubicTo(t1Pt, t2Pt, endPt);
200 path.close();
201 return endPt;
202 }
203
204 void drawPath(SkPath& path, SkCanvas* canvas, SkColor color,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000205 const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000206 SkPaint::Style style, SkPath::FillType fill,
207 SkScalar strokeWidth) {
208 path.setFillType(fill);
209 SkPaint paint;
210 paint.setStrokeCap(cap);
211 paint.setStrokeWidth(strokeWidth);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000212 paint.setStrokeJoin(join);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000213 paint.setColor(color);
214 paint.setStyle(style);
215 canvas->save();
216 canvas->clipRect(clip);
217 canvas->drawPath(path, paint);
218 canvas->restore();
219 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000220
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000221 virtual void onDraw(SkCanvas* canvas) {
mtkleindbfd7ab2016-09-01 11:24:54 -0700222 constexpr AddSegmentFunc gSegmentFunctions[] = {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000223 AddMove,
224 AddMoveClose,
225 AddDegenLine,
226 AddMoveDegenLine,
227 AddMoveDegenLineClose,
228 AddDegenQuad,
229 AddMoveDegenQuad,
230 AddMoveDegenQuadClose,
231 AddDegenCubic,
232 AddMoveDegenCubic,
233 AddMoveDegenCubicClose,
234 AddClose,
235 AddLine,
236 AddMoveLine,
237 AddMoveLineClose,
238 AddQuad,
239 AddMoveQuad,
240 AddMoveQuadClose,
241 AddCubic,
242 AddMoveCubic,
243 AddMoveCubicClose
244 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700245 const char* gSegmentNames[] = {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000246 "Move",
247 "MoveClose",
248 "DegenLine",
249 "MoveDegenLine",
250 "MoveDegenLineClose",
251 "DegenQuad",
252 "MoveDegenQuad",
253 "MoveDegenQuadClose",
254 "DegenCubic",
255 "MoveDegenCubic",
256 "MoveDegenCubicClose",
257 "Close",
258 "Line",
259 "MoveLine",
260 "MoveLineClose",
261 "Quad",
262 "MoveQuad",
263 "MoveQuadClose",
264 "Cubic",
265 "MoveCubic",
266 "MoveCubicClose"
267 };
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000268
269 struct FillAndName {
270 SkPath::FillType fFill;
271 const char* fName;
272 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700273 constexpr FillAndName gFills[] = {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000274 {SkPath::kWinding_FillType, "Winding"},
275 {SkPath::kEvenOdd_FillType, "Even / Odd"},
276 {SkPath::kInverseWinding_FillType, "Inverse Winding"},
277 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}
278 };
279 struct StyleAndName {
280 SkPaint::Style fStyle;
281 const char* fName;
282 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700283 constexpr StyleAndName gStyles[] = {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000284 {SkPaint::kFill_Style, "Fill"},
285 {SkPaint::kStroke_Style, "Stroke 10"},
286 {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
287 };
288 struct CapAndName {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000289 SkPaint::Cap fCap;
290 SkPaint::Join fJoin;
291 const char* fName;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000292 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700293 constexpr CapAndName gCaps[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000294 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
295 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
296 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000297 };
298
299 SkPaint titlePaint;
300 titlePaint.setColor(SK_ColorBLACK);
301 titlePaint.setAntiAlias(true);
Mike Kleinea3f0142019-03-20 11:12:10 -0500302 SkFont font(ToolUtils::create_portable_typeface(), 15);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000303 const char title[] = "Random Paths Drawn Into Rectangle Clips With "
304 "Indicated Style, Fill and Linecaps, "
305 "with Stroke width 6";
Mike Reed1af9b482019-01-07 11:01:57 -0500306 canvas->drawString(title, 20, 20, font, titlePaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000307
scroggof9d61012014-12-15 12:54:51 -0800308 SkRandom rand;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000309 SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
310 canvas->save();
311 canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
312 canvas->save();
313 unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
314 unsigned numCaps = SK_ARRAY_COUNT(gCaps);
315 unsigned numStyles = SK_ARRAY_COUNT(gStyles);
316 unsigned numFills = SK_ARRAY_COUNT(gFills);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000317 for (size_t row = 0; row < 6; ++row) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000318 if (0 < row) {
319 canvas->translate(0, rect.height() + 100*SK_Scalar1);
320 }
321 canvas->save();
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000322 for (size_t column = 0; column < 4; ++column) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000323 if (0 < column) {
324 canvas->translate(rect.width() + 4*SK_Scalar1, 0);
325 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000326
Mike Kleinea3f0142019-03-20 11:12:10 -0500327 SkColor color = ToolUtils::color_to_565(0xff007000);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000328 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
329 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
330 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
331 SkPath path;
332 unsigned s1 = (rand.nextU() >> 16) % numSegments;
333 unsigned s2 = (rand.nextU() >> 16) % numSegments;
334 unsigned s3 = (rand.nextU() >> 16) % numSegments;
335 unsigned s4 = (rand.nextU() >> 16) % numSegments;
336 unsigned s5 = (rand.nextU() >> 16) % numSegments;
337 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
338 pt = gSegmentFunctions[s1](path, pt);
339 pt = gSegmentFunctions[s2](path, pt);
340 pt = gSegmentFunctions[s3](path, pt);
341 pt = gSegmentFunctions[s4](path, pt);
342 pt = gSegmentFunctions[s5](path, pt);
343
344 this->drawPath(path, canvas, color, rect,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000345 cap.fCap, cap.fJoin, style.fStyle,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000346 fill.fFill, SK_Scalar1*6);
347
348 SkPaint rectPaint;
349 rectPaint.setColor(SK_ColorBLACK);
350 rectPaint.setStyle(SkPaint::kStroke_Style);
351 rectPaint.setStrokeWidth(-1);
352 rectPaint.setAntiAlias(true);
353 canvas->drawRect(rect, rectPaint);
354
355 SkPaint labelPaint;
356 labelPaint.setColor(color);
357 labelPaint.setAntiAlias(true);
Mike Reed1af9b482019-01-07 11:01:57 -0500358 font.setSize(10);
359 canvas->drawString(style.fName, 0, rect.height() + 12, font, labelPaint);
360 canvas->drawString(fill.fName, 0, rect.height() + 24, font, labelPaint);
361 canvas->drawString(cap.fName, 0, rect.height() + 36, font, labelPaint);
362 canvas->drawString(gSegmentNames[s1], 0, rect.height() + 48, font, labelPaint);
363 canvas->drawString(gSegmentNames[s2], 0, rect.height() + 60, font, labelPaint);
364 canvas->drawString(gSegmentNames[s3], 0, rect.height() + 72, font, labelPaint);
365 canvas->drawString(gSegmentNames[s4], 0, rect.height() + 84, font, labelPaint);
366 canvas->drawString(gSegmentNames[s5], 0, rect.height() + 96, font, labelPaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000367 }
368 canvas->restore();
369 }
370 canvas->restore();
371 canvas->restore();
372 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000373
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000374private:
375 typedef GM INHERITED;
376};
377
378//////////////////////////////////////////////////////////////////////////////
379
Hal Canarye964c182019-01-23 10:22:01 -0500380DEF_GM( return new DegenerateSegmentsGM; )
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000381
382}