blob: 029ac242a7adca66d7f279a1dca3d876042ed682 [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"
Mike Reed92f6eb12020-08-25 11:48:41 -040013#include "include/core/SkPathBuilder.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 {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000027 struct PathAndName {
28 SkPath fPath;
29 const char* fName1;
30 const char* fName2;
31 };
32
Hal Canaryfa3305a2019-07-18 12:36:54 -040033 SkString onShortName() override { return SkString("degeneratesegments"); }
rmistry@google.comd6176b02012-08-23 18:14:13 +000034
Hal Canaryfa3305a2019-07-18 12:36:54 -040035 SkISize onISize() override { return {896, 930}; }
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000036
Mike Reed92f6eb12020-08-25 11:48:41 -040037 typedef SkPoint (*AddSegmentFunc)(SkPathBuilder&, SkPoint&);
rmistry@google.comd6176b02012-08-23 18:14:13 +000038
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000039 // We need to use explicit commands here, instead of addPath, because we
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000040 // do not want the moveTo that is added at the beginning of a path to
41 // appear in the appended path.
Mike Reed92f6eb12020-08-25 11:48:41 -040042 static SkPoint AddMove(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000043 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
44 path.moveTo(moveToPt);
45 return moveToPt;
46 }
47
Mike Reed92f6eb12020-08-25 11:48:41 -040048 static SkPoint AddMoveClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000049 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
50 path.moveTo(moveToPt);
51 path.close();
52 return moveToPt;
53 }
54
Mike Reed92f6eb12020-08-25 11:48:41 -040055 static SkPoint AddDegenLine(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000056 path.lineTo(startPt);
57 return startPt;
58 }
59
Mike Reed92f6eb12020-08-25 11:48:41 -040060 static SkPoint AddMoveDegenLine(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000061 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
62 path.moveTo(moveToPt);
63 path.lineTo(moveToPt);
64 return moveToPt;
65 }
66
Mike Reed92f6eb12020-08-25 11:48:41 -040067 static SkPoint AddMoveDegenLineClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000068 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
69 path.moveTo(moveToPt);
70 path.lineTo(moveToPt);
71 path.close();
72 return moveToPt;
73 }
74
Mike Reed92f6eb12020-08-25 11:48:41 -040075 static SkPoint AddDegenQuad(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000076 path.quadTo(startPt, startPt);
77 return startPt;
78 }
79
Mike Reed92f6eb12020-08-25 11:48:41 -040080 static SkPoint AddMoveDegenQuad(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000081 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
82 path.moveTo(moveToPt);
83 path.quadTo(moveToPt, moveToPt);
84 return moveToPt;
85 }
86
Mike Reed92f6eb12020-08-25 11:48:41 -040087 static SkPoint AddMoveDegenQuadClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000088 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
89 path.moveTo(moveToPt);
90 path.quadTo(moveToPt, moveToPt);
91 path.close();
92 return moveToPt;
93 }
94
Mike Reed92f6eb12020-08-25 11:48:41 -040095 static SkPoint AddDegenCubic(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000096 path.cubicTo(startPt, startPt, startPt);
97 return startPt;
98 }
99
Mike Reed92f6eb12020-08-25 11:48:41 -0400100 static SkPoint AddMoveDegenCubic(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000101 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
102 path.moveTo(moveToPt);
103 path.cubicTo(moveToPt, moveToPt, moveToPt);
104 return moveToPt;
105 }
106
Mike Reed92f6eb12020-08-25 11:48:41 -0400107 static SkPoint AddMoveDegenCubicClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000108 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
109 path.moveTo(moveToPt);
110 path.cubicTo(moveToPt, moveToPt, moveToPt);
111 path.close();
112 return moveToPt;
113 }
114
Mike Reed92f6eb12020-08-25 11:48:41 -0400115 static SkPoint AddClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000116 path.close();
117 return startPt;
118 }
119
Mike Reed92f6eb12020-08-25 11:48:41 -0400120 static SkPoint AddLine(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000121 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
122 path.lineTo(endPt);
123 return endPt;
124 }
125
Mike Reed92f6eb12020-08-25 11:48:41 -0400126 static SkPoint AddMoveLine(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000127 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
128 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
129 path.moveTo(moveToPt);
130 path.lineTo(endPt);
131 return endPt;
132 }
133
Mike Reed92f6eb12020-08-25 11:48:41 -0400134 static SkPoint AddMoveLineClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000135 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
136 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
137 path.moveTo(moveToPt);
138 path.lineTo(endPt);
139 path.close();
140 return endPt;
141 }
142
Mike Reed92f6eb12020-08-25 11:48:41 -0400143 static SkPoint AddQuad(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000144 SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
145 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
146 path.quadTo(midPt, endPt);
147 return endPt;
148 }
149
Mike Reed92f6eb12020-08-25 11:48:41 -0400150 static SkPoint AddMoveQuad(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000151 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
152 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
153 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
154 path.moveTo(moveToPt);
155 path.quadTo(midPt, endPt);
156 return endPt;
157 }
158
Mike Reed92f6eb12020-08-25 11:48:41 -0400159 static SkPoint AddMoveQuadClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000160 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
161 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
162 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
163 path.moveTo(moveToPt);
164 path.quadTo(midPt, endPt);
165 path.close();
166 return endPt;
167 }
168
Mike Reed92f6eb12020-08-25 11:48:41 -0400169 static SkPoint AddCubic(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000170 SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
171 SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
172 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
173 path.cubicTo(t1Pt, t2Pt, endPt);
174 return endPt;
175 }
176
Mike Reed92f6eb12020-08-25 11:48:41 -0400177 static SkPoint AddMoveCubic(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000178 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
179 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
180 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
181 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
182 path.moveTo(moveToPt);
183 path.cubicTo(t1Pt, t2Pt, endPt);
184 return endPt;
185 }
186
Mike Reed92f6eb12020-08-25 11:48:41 -0400187 static SkPoint AddMoveCubicClose(SkPathBuilder& path, SkPoint& startPt) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000188 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
189 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
190 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
191 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
192 path.moveTo(moveToPt);
193 path.cubicTo(t1Pt, t2Pt, endPt);
194 path.close();
195 return endPt;
196 }
197
Mike Reed92f6eb12020-08-25 11:48:41 -0400198 void drawPath(SkPath path, SkCanvas* canvas, SkColor color,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000199 const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
Mike Reed7d34dc72019-11-26 12:17:17 -0500200 SkPaint::Style style, SkPathFillType fill,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000201 SkScalar strokeWidth) {
202 path.setFillType(fill);
203 SkPaint paint;
204 paint.setStrokeCap(cap);
205 paint.setStrokeWidth(strokeWidth);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000206 paint.setStrokeJoin(join);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000207 paint.setColor(color);
208 paint.setStyle(style);
209 canvas->save();
210 canvas->clipRect(clip);
211 canvas->drawPath(path, paint);
212 canvas->restore();
213 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000214
Hal Canaryfa3305a2019-07-18 12:36:54 -0400215 void onDraw(SkCanvas* canvas) override {
216 constexpr AddSegmentFunc gSegmentFunctions[] = {
217 AddMove,
218 AddMoveClose,
219 AddDegenLine,
220 AddMoveDegenLine,
221 AddMoveDegenLineClose,
222 AddDegenQuad,
223 AddMoveDegenQuad,
224 AddMoveDegenQuadClose,
225 AddDegenCubic,
226 AddMoveDegenCubic,
227 AddMoveDegenCubicClose,
228 AddClose,
229 AddLine,
230 AddMoveLine,
231 AddMoveLineClose,
232 AddQuad,
233 AddMoveQuad,
234 AddMoveQuadClose,
235 AddCubic,
236 AddMoveCubic,
237 AddMoveCubicClose
238 };
239 const char* gSegmentNames[] = {
240 "Move",
241 "MoveClose",
242 "DegenLine",
243 "MoveDegenLine",
244 "MoveDegenLineClose",
245 "DegenQuad",
246 "MoveDegenQuad",
247 "MoveDegenQuadClose",
248 "DegenCubic",
249 "MoveDegenCubic",
250 "MoveDegenCubicClose",
251 "Close",
252 "Line",
253 "MoveLine",
254 "MoveLineClose",
255 "Quad",
256 "MoveQuad",
257 "MoveQuadClose",
258 "Cubic",
259 "MoveCubic",
260 "MoveCubicClose"
261 };
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000262
263 struct FillAndName {
Mike Reed7d34dc72019-11-26 12:17:17 -0500264 SkPathFillType fFill;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000265 const char* fName;
266 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700267 constexpr FillAndName gFills[] = {
Mike Reed7d34dc72019-11-26 12:17:17 -0500268 {SkPathFillType::kWinding, "Winding"},
269 {SkPathFillType::kEvenOdd, "Even / Odd"},
270 {SkPathFillType::kInverseWinding, "Inverse Winding"},
271 {SkPathFillType::kInverseEvenOdd, "Inverse Even / Odd"}
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000272 };
273 struct StyleAndName {
274 SkPaint::Style fStyle;
275 const char* fName;
276 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700277 constexpr StyleAndName gStyles[] = {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000278 {SkPaint::kFill_Style, "Fill"},
279 {SkPaint::kStroke_Style, "Stroke 10"},
280 {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
281 };
282 struct CapAndName {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000283 SkPaint::Cap fCap;
284 SkPaint::Join fJoin;
285 const char* fName;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000286 };
mtkleindbfd7ab2016-09-01 11:24:54 -0700287 constexpr CapAndName gCaps[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000288 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
289 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
290 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000291 };
292
293 SkPaint titlePaint;
294 titlePaint.setColor(SK_ColorBLACK);
295 titlePaint.setAntiAlias(true);
Mike Kleinea3f0142019-03-20 11:12:10 -0500296 SkFont font(ToolUtils::create_portable_typeface(), 15);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000297 const char title[] = "Random Paths Drawn Into Rectangle Clips With "
298 "Indicated Style, Fill and Linecaps, "
299 "with Stroke width 6";
Mike Reed1af9b482019-01-07 11:01:57 -0500300 canvas->drawString(title, 20, 20, font, 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
Mike Kleinea3f0142019-03-20 11:12:10 -0500321 SkColor color = ToolUtils::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];
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000325 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);
Mike Reed92f6eb12020-08-25 11:48:41 -0400331 SkPathBuilder path;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000332 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
Mike Reed92f6eb12020-08-25 11:48:41 -0400338 this->drawPath(path.detach(), 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);
Mike Reed1af9b482019-01-07 11:01:57 -0500352 font.setSize(10);
353 canvas->drawString(style.fName, 0, rect.height() + 12, font, labelPaint);
354 canvas->drawString(fill.fName, 0, rect.height() + 24, font, labelPaint);
355 canvas->drawString(cap.fName, 0, rect.height() + 36, font, labelPaint);
356 canvas->drawString(gSegmentNames[s1], 0, rect.height() + 48, font, labelPaint);
357 canvas->drawString(gSegmentNames[s2], 0, rect.height() + 60, font, labelPaint);
358 canvas->drawString(gSegmentNames[s3], 0, rect.height() + 72, font, labelPaint);
359 canvas->drawString(gSegmentNames[s4], 0, rect.height() + 84, font, labelPaint);
360 canvas->drawString(gSegmentNames[s5], 0, rect.height() + 96, font, labelPaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000361 }
362 canvas->restore();
363 }
364 canvas->restore();
365 canvas->restore();
366 }
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000367};
368
369//////////////////////////////////////////////////////////////////////////////
370
Hal Canarye964c182019-01-23 10:22:01 -0500371DEF_GM( return new DegenerateSegmentsGM; )
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000372
John Stilesa6841be2020-08-06 14:11:56 -0400373} // namespace skiagm