blob: f96d0496d2f24dfd74a21cd1204dab4f03e0242a [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 {
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
37 typedef SkPoint (*AddSegmentFunc)(SkPath&, 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.
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000042 static SkPoint AddMove(SkPath& path, SkPoint& startPt) {
43 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
44 path.moveTo(moveToPt);
45 return moveToPt;
46 }
47
48 static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) {
49 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
50 path.moveTo(moveToPt);
51 path.close();
52 return moveToPt;
53 }
54
55 static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
56 path.lineTo(startPt);
57 return startPt;
58 }
59
60 static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) {
61 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
62 path.moveTo(moveToPt);
63 path.lineTo(moveToPt);
64 return moveToPt;
65 }
66
67 static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) {
68 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
75 static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
76 path.quadTo(startPt, startPt);
77 return startPt;
78 }
79
80 static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) {
81 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
82 path.moveTo(moveToPt);
83 path.quadTo(moveToPt, moveToPt);
84 return moveToPt;
85 }
86
87 static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) {
88 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
95 static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
96 path.cubicTo(startPt, startPt, startPt);
97 return startPt;
98 }
99
100 static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) {
101 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
102 path.moveTo(moveToPt);
103 path.cubicTo(moveToPt, moveToPt, moveToPt);
104 return moveToPt;
105 }
106
107 static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) {
108 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
115 static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
116 path.close();
117 return startPt;
118 }
119
120 static SkPoint AddLine(SkPath& path, SkPoint& startPt) {
121 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
122 path.lineTo(endPt);
123 return endPt;
124 }
125
126 static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) {
127 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
134 static SkPoint AddMoveLineClose(SkPath& path, SkPoint& startPt) {
135 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
143 static SkPoint AddQuad(SkPath& path, SkPoint& startPt) {
144 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
150 static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) {
151 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
159 static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) {
160 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
169 static SkPoint AddCubic(SkPath& path, SkPoint& startPt) {
170 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
177 static SkPoint AddMoveCubic(SkPath& path, SkPoint& startPt) {
178 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
187 static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) {
188 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
198 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];
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);
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
373}