blob: e5ca18796adfa72611dda0ce6fec8d08d0fd25ad [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"
10#include "SkRandom.h"
11
12namespace skiagm {
13
14class DegenerateSegmentsGM : public GM {
15public:
16 DegenerateSegmentsGM() {}
17
18protected:
19 struct PathAndName {
20 SkPath fPath;
21 const char* fName1;
22 const char* fName2;
23 };
24
25 SkString onShortName() {
26 return SkString("degeneratesegments");
27 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000028
tfarinaf5393182014-06-09 23:59:03 -070029 SkISize onISize() { return SkISize::Make(896, 930); }
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000030
31 typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
rmistry@google.comd6176b02012-08-23 18:14:13 +000032
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000033 // We need to use explicit commands here, instead of addPath, because we
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000034 // do not want the moveTo that is added at the beginning of a path to
35 // appear in the appended path.
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000036 static SkPoint AddMove(SkPath& path, SkPoint& startPt) {
37 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
38 path.moveTo(moveToPt);
39 return moveToPt;
40 }
41
42 static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) {
43 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
44 path.moveTo(moveToPt);
45 path.close();
46 return moveToPt;
47 }
48
49 static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
50 path.lineTo(startPt);
51 return startPt;
52 }
53
54 static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) {
55 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
56 path.moveTo(moveToPt);
57 path.lineTo(moveToPt);
58 return moveToPt;
59 }
60
61 static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) {
62 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
63 path.moveTo(moveToPt);
64 path.lineTo(moveToPt);
65 path.close();
66 return moveToPt;
67 }
68
69 static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
70 path.quadTo(startPt, startPt);
71 return startPt;
72 }
73
74 static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) {
75 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
76 path.moveTo(moveToPt);
77 path.quadTo(moveToPt, moveToPt);
78 return moveToPt;
79 }
80
81 static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) {
82 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
83 path.moveTo(moveToPt);
84 path.quadTo(moveToPt, moveToPt);
85 path.close();
86 return moveToPt;
87 }
88
89 static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
90 path.cubicTo(startPt, startPt, startPt);
91 return startPt;
92 }
93
94 static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) {
95 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
96 path.moveTo(moveToPt);
97 path.cubicTo(moveToPt, moveToPt, moveToPt);
98 return moveToPt;
99 }
100
101 static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) {
102 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
103 path.moveTo(moveToPt);
104 path.cubicTo(moveToPt, moveToPt, moveToPt);
105 path.close();
106 return moveToPt;
107 }
108
109 static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
110 path.close();
111 return startPt;
112 }
113
114 static SkPoint AddLine(SkPath& path, SkPoint& startPt) {
115 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
116 path.lineTo(endPt);
117 return endPt;
118 }
119
120 static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) {
121 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
122 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
123 path.moveTo(moveToPt);
124 path.lineTo(endPt);
125 return endPt;
126 }
127
128 static SkPoint AddMoveLineClose(SkPath& path, SkPoint& startPt) {
129 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
130 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
131 path.moveTo(moveToPt);
132 path.lineTo(endPt);
133 path.close();
134 return endPt;
135 }
136
137 static SkPoint AddQuad(SkPath& path, SkPoint& startPt) {
138 SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
139 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
140 path.quadTo(midPt, endPt);
141 return endPt;
142 }
143
144 static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) {
145 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
146 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
147 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
148 path.moveTo(moveToPt);
149 path.quadTo(midPt, endPt);
150 return endPt;
151 }
152
153 static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) {
154 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
155 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
156 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
157 path.moveTo(moveToPt);
158 path.quadTo(midPt, endPt);
159 path.close();
160 return endPt;
161 }
162
163 static SkPoint AddCubic(SkPath& path, SkPoint& startPt) {
164 SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
165 SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
166 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
167 path.cubicTo(t1Pt, t2Pt, endPt);
168 return endPt;
169 }
170
171 static SkPoint AddMoveCubic(SkPath& path, SkPoint& startPt) {
172 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
173 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
174 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
175 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
176 path.moveTo(moveToPt);
177 path.cubicTo(t1Pt, t2Pt, endPt);
178 return endPt;
179 }
180
181 static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) {
182 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
183 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
184 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
185 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
186 path.moveTo(moveToPt);
187 path.cubicTo(t1Pt, t2Pt, endPt);
188 path.close();
189 return endPt;
190 }
191
192 void drawPath(SkPath& path, SkCanvas* canvas, SkColor color,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000193 const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000194 SkPaint::Style style, SkPath::FillType fill,
195 SkScalar strokeWidth) {
196 path.setFillType(fill);
197 SkPaint paint;
198 paint.setStrokeCap(cap);
199 paint.setStrokeWidth(strokeWidth);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000200 paint.setStrokeJoin(join);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000201 paint.setColor(color);
202 paint.setStyle(style);
203 canvas->save();
204 canvas->clipRect(clip);
205 canvas->drawPath(path, paint);
206 canvas->restore();
207 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000208
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000209 virtual void onDraw(SkCanvas* canvas) {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000210 static const AddSegmentFunc gSegmentFunctions[] = {
211 AddMove,
212 AddMoveClose,
213 AddDegenLine,
214 AddMoveDegenLine,
215 AddMoveDegenLineClose,
216 AddDegenQuad,
217 AddMoveDegenQuad,
218 AddMoveDegenQuadClose,
219 AddDegenCubic,
220 AddMoveDegenCubic,
221 AddMoveDegenCubicClose,
222 AddClose,
223 AddLine,
224 AddMoveLine,
225 AddMoveLineClose,
226 AddQuad,
227 AddMoveQuad,
228 AddMoveQuadClose,
229 AddCubic,
230 AddMoveCubic,
231 AddMoveCubicClose
232 };
233 static const char* gSegmentNames[] = {
234 "Move",
235 "MoveClose",
236 "DegenLine",
237 "MoveDegenLine",
238 "MoveDegenLineClose",
239 "DegenQuad",
240 "MoveDegenQuad",
241 "MoveDegenQuadClose",
242 "DegenCubic",
243 "MoveDegenCubic",
244 "MoveDegenCubicClose",
245 "Close",
246 "Line",
247 "MoveLine",
248 "MoveLineClose",
249 "Quad",
250 "MoveQuad",
251 "MoveQuadClose",
252 "Cubic",
253 "MoveCubic",
254 "MoveCubicClose"
255 };
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000256
257 struct FillAndName {
258 SkPath::FillType fFill;
259 const char* fName;
260 };
261 static const FillAndName gFills[] = {
262 {SkPath::kWinding_FillType, "Winding"},
263 {SkPath::kEvenOdd_FillType, "Even / Odd"},
264 {SkPath::kInverseWinding_FillType, "Inverse Winding"},
265 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}
266 };
267 struct StyleAndName {
268 SkPaint::Style fStyle;
269 const char* fName;
270 };
271 static const StyleAndName gStyles[] = {
272 {SkPaint::kFill_Style, "Fill"},
273 {SkPaint::kStroke_Style, "Stroke 10"},
274 {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
275 };
276 struct CapAndName {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000277 SkPaint::Cap fCap;
278 SkPaint::Join fJoin;
279 const char* fName;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000280 };
281 static const CapAndName gCaps[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000282 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
283 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
284 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000285 };
286
287 SkPaint titlePaint;
288 titlePaint.setColor(SK_ColorBLACK);
289 titlePaint.setAntiAlias(true);
caryclark5fb6bd42014-06-23 11:25:00 -0700290 sk_tool_utils::set_portable_typeface(&titlePaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000291 titlePaint.setLCDRenderText(true);
292 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
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000320 SkColor color = 0xff007000;
321 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);
caryclark5fb6bd42014-06-23 11:25:00 -0700351 sk_tool_utils::set_portable_typeface(&labelPaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000352 labelPaint.setLCDRenderText(true);
353 labelPaint.setTextSize(10 * SK_Scalar1);
354 canvas->drawText(style.fName,
355 strlen(style.fName),
356 0, rect.height() + 12 * SK_Scalar1,
357 labelPaint);
358 canvas->drawText(fill.fName,
359 strlen(fill.fName),
360 0, rect.height() + 24 * SK_Scalar1,
361 labelPaint);
362 canvas->drawText(cap.fName,
363 strlen(cap.fName),
364 0, rect.height() + 36 * SK_Scalar1,
365 labelPaint);
366 canvas->drawText(gSegmentNames[s1],
367 strlen(gSegmentNames[s1]),
368 0, rect.height() + 48 * SK_Scalar1,
369 labelPaint);
370 canvas->drawText(gSegmentNames[s2],
371 strlen(gSegmentNames[s2]),
372 0, rect.height() + 60 * SK_Scalar1,
373 labelPaint);
374 canvas->drawText(gSegmentNames[s3],
375 strlen(gSegmentNames[s3]),
376 0, rect.height() + 72 * SK_Scalar1,
377 labelPaint);
378 canvas->drawText(gSegmentNames[s4],
379 strlen(gSegmentNames[s4]),
380 0, rect.height() + 84 * SK_Scalar1,
381 labelPaint);
382 canvas->drawText(gSegmentNames[s5],
383 strlen(gSegmentNames[s5]),
384 0, rect.height() + 96 * SK_Scalar1,
385 labelPaint);
386 }
387 canvas->restore();
388 }
389 canvas->restore();
390 canvas->restore();
391 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000392
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000393private:
394 typedef GM INHERITED;
395};
396
397//////////////////////////////////////////////////////////////////////////////
398
399static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
400static GMRegistry reg(MyFactory);
401
402}