blob: 17bf83bddcba985037b2b040ca140ae5fb33b010 [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
commit-bot@chromium.orga90c6802014-04-30 13:20:45 +000025 virtual uint32_t onGetFlags() const SK_OVERRIDE {
26 return kSkipTiled_Flag;
27 }
28
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000029 SkString onShortName() {
30 return SkString("degeneratesegments");
31 }
rmistry@google.comd6176b02012-08-23 18:14:13 +000032
tfarinaf5393182014-06-09 23:59:03 -070033 SkISize onISize() { return SkISize::Make(896, 930); }
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000034
35 typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
rmistry@google.comd6176b02012-08-23 18:14:13 +000036
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000037 // We need to use explicit commands here, instead of addPath, because we
schenney@chromium.org6630d8d2012-01-04 21:05:51 +000038 // do not want the moveTo that is added at the beginning of a path to
39 // appear in the appended path.
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000040 static SkPoint AddMove(SkPath& path, SkPoint& startPt) {
41 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
42 path.moveTo(moveToPt);
43 return moveToPt;
44 }
45
46 static SkPoint AddMoveClose(SkPath& path, SkPoint& startPt) {
47 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
48 path.moveTo(moveToPt);
49 path.close();
50 return moveToPt;
51 }
52
53 static SkPoint AddDegenLine(SkPath& path, SkPoint& startPt) {
54 path.lineTo(startPt);
55 return startPt;
56 }
57
58 static SkPoint AddMoveDegenLine(SkPath& path, SkPoint& startPt) {
59 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
60 path.moveTo(moveToPt);
61 path.lineTo(moveToPt);
62 return moveToPt;
63 }
64
65 static SkPoint AddMoveDegenLineClose(SkPath& path, SkPoint& startPt) {
66 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
67 path.moveTo(moveToPt);
68 path.lineTo(moveToPt);
69 path.close();
70 return moveToPt;
71 }
72
73 static SkPoint AddDegenQuad(SkPath& path, SkPoint& startPt) {
74 path.quadTo(startPt, startPt);
75 return startPt;
76 }
77
78 static SkPoint AddMoveDegenQuad(SkPath& path, SkPoint& startPt) {
79 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
80 path.moveTo(moveToPt);
81 path.quadTo(moveToPt, moveToPt);
82 return moveToPt;
83 }
84
85 static SkPoint AddMoveDegenQuadClose(SkPath& path, SkPoint& startPt) {
86 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
87 path.moveTo(moveToPt);
88 path.quadTo(moveToPt, moveToPt);
89 path.close();
90 return moveToPt;
91 }
92
93 static SkPoint AddDegenCubic(SkPath& path, SkPoint& startPt) {
94 path.cubicTo(startPt, startPt, startPt);
95 return startPt;
96 }
97
98 static SkPoint AddMoveDegenCubic(SkPath& path, SkPoint& startPt) {
99 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
100 path.moveTo(moveToPt);
101 path.cubicTo(moveToPt, moveToPt, moveToPt);
102 return moveToPt;
103 }
104
105 static SkPoint AddMoveDegenCubicClose(SkPath& path, SkPoint& startPt) {
106 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
107 path.moveTo(moveToPt);
108 path.cubicTo(moveToPt, moveToPt, moveToPt);
109 path.close();
110 return moveToPt;
111 }
112
113 static SkPoint AddClose(SkPath& path, SkPoint& startPt) {
114 path.close();
115 return startPt;
116 }
117
118 static SkPoint AddLine(SkPath& path, SkPoint& startPt) {
119 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
120 path.lineTo(endPt);
121 return endPt;
122 }
123
124 static SkPoint AddMoveLine(SkPath& path, SkPoint& startPt) {
125 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
126 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
127 path.moveTo(moveToPt);
128 path.lineTo(endPt);
129 return endPt;
130 }
131
132 static SkPoint AddMoveLineClose(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 path.close();
138 return endPt;
139 }
140
141 static SkPoint AddQuad(SkPath& path, SkPoint& startPt) {
142 SkPoint midPt = startPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
143 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
144 path.quadTo(midPt, endPt);
145 return endPt;
146 }
147
148 static SkPoint AddMoveQuad(SkPath& path, SkPoint& startPt) {
149 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
150 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
151 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
152 path.moveTo(moveToPt);
153 path.quadTo(midPt, endPt);
154 return endPt;
155 }
156
157 static SkPoint AddMoveQuadClose(SkPath& path, SkPoint& startPt) {
158 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
159 SkPoint midPt = moveToPt + SkPoint::Make(20*SK_Scalar1, 5*SK_Scalar1);
160 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
161 path.moveTo(moveToPt);
162 path.quadTo(midPt, endPt);
163 path.close();
164 return endPt;
165 }
166
167 static SkPoint AddCubic(SkPath& path, SkPoint& startPt) {
168 SkPoint t1Pt = startPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
169 SkPoint t2Pt = startPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
170 SkPoint endPt = startPt + SkPoint::Make(40*SK_Scalar1, 0);
171 path.cubicTo(t1Pt, t2Pt, endPt);
172 return endPt;
173 }
174
175 static SkPoint AddMoveCubic(SkPath& path, SkPoint& startPt) {
176 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
177 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
178 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
179 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
180 path.moveTo(moveToPt);
181 path.cubicTo(t1Pt, t2Pt, endPt);
182 return endPt;
183 }
184
185 static SkPoint AddMoveCubicClose(SkPath& path, SkPoint& startPt) {
186 SkPoint moveToPt = startPt + SkPoint::Make(0, 10*SK_Scalar1);
187 SkPoint t1Pt = moveToPt + SkPoint::Make(15*SK_Scalar1, 5*SK_Scalar1);
188 SkPoint t2Pt = moveToPt + SkPoint::Make(25*SK_Scalar1, 5*SK_Scalar1);
189 SkPoint endPt = moveToPt + SkPoint::Make(40*SK_Scalar1, 0);
190 path.moveTo(moveToPt);
191 path.cubicTo(t1Pt, t2Pt, endPt);
192 path.close();
193 return endPt;
194 }
195
196 void drawPath(SkPath& path, SkCanvas* canvas, SkColor color,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000197 const SkRect& clip, SkPaint::Cap cap, SkPaint::Join join,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000198 SkPaint::Style style, SkPath::FillType fill,
199 SkScalar strokeWidth) {
200 path.setFillType(fill);
201 SkPaint paint;
202 paint.setStrokeCap(cap);
203 paint.setStrokeWidth(strokeWidth);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000204 paint.setStrokeJoin(join);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000205 paint.setColor(color);
206 paint.setStyle(style);
207 canvas->save();
208 canvas->clipRect(clip);
209 canvas->drawPath(path, paint);
210 canvas->restore();
211 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000212
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000213 virtual void onDraw(SkCanvas* canvas) {
schenney@chromium.org6630d8d2012-01-04 21:05:51 +0000214 static const AddSegmentFunc gSegmentFunctions[] = {
215 AddMove,
216 AddMoveClose,
217 AddDegenLine,
218 AddMoveDegenLine,
219 AddMoveDegenLineClose,
220 AddDegenQuad,
221 AddMoveDegenQuad,
222 AddMoveDegenQuadClose,
223 AddDegenCubic,
224 AddMoveDegenCubic,
225 AddMoveDegenCubicClose,
226 AddClose,
227 AddLine,
228 AddMoveLine,
229 AddMoveLineClose,
230 AddQuad,
231 AddMoveQuad,
232 AddMoveQuadClose,
233 AddCubic,
234 AddMoveCubic,
235 AddMoveCubicClose
236 };
237 static const char* gSegmentNames[] = {
238 "Move",
239 "MoveClose",
240 "DegenLine",
241 "MoveDegenLine",
242 "MoveDegenLineClose",
243 "DegenQuad",
244 "MoveDegenQuad",
245 "MoveDegenQuadClose",
246 "DegenCubic",
247 "MoveDegenCubic",
248 "MoveDegenCubicClose",
249 "Close",
250 "Line",
251 "MoveLine",
252 "MoveLineClose",
253 "Quad",
254 "MoveQuad",
255 "MoveQuadClose",
256 "Cubic",
257 "MoveCubic",
258 "MoveCubicClose"
259 };
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000260
261 struct FillAndName {
262 SkPath::FillType fFill;
263 const char* fName;
264 };
265 static const FillAndName gFills[] = {
266 {SkPath::kWinding_FillType, "Winding"},
267 {SkPath::kEvenOdd_FillType, "Even / Odd"},
268 {SkPath::kInverseWinding_FillType, "Inverse Winding"},
269 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}
270 };
271 struct StyleAndName {
272 SkPaint::Style fStyle;
273 const char* fName;
274 };
275 static const StyleAndName gStyles[] = {
276 {SkPaint::kFill_Style, "Fill"},
277 {SkPaint::kStroke_Style, "Stroke 10"},
278 {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
279 };
280 struct CapAndName {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000281 SkPaint::Cap fCap;
282 SkPaint::Join fJoin;
283 const char* fName;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000284 };
285 static const CapAndName gCaps[] = {
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000286 {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
287 {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
288 {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000289 };
290
291 SkPaint titlePaint;
292 titlePaint.setColor(SK_ColorBLACK);
293 titlePaint.setAntiAlias(true);
caryclark5fb6bd42014-06-23 11:25:00 -0700294 sk_tool_utils::set_portable_typeface(&titlePaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000295 titlePaint.setLCDRenderText(true);
296 titlePaint.setTextSize(15 * SK_Scalar1);
297 const char title[] = "Random Paths Drawn Into Rectangle Clips With "
298 "Indicated Style, Fill and Linecaps, "
299 "with Stroke width 6";
300 canvas->drawText(title, strlen(title),
301 20 * SK_Scalar1,
302 20 * SK_Scalar1,
303 titlePaint);
304
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000305 SkLCGRandom rand;
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000306 SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
307 canvas->save();
308 canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
309 canvas->save();
310 unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
311 unsigned numCaps = SK_ARRAY_COUNT(gCaps);
312 unsigned numStyles = SK_ARRAY_COUNT(gStyles);
313 unsigned numFills = SK_ARRAY_COUNT(gFills);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000314 for (size_t row = 0; row < 6; ++row) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000315 if (0 < row) {
316 canvas->translate(0, rect.height() + 100*SK_Scalar1);
317 }
318 canvas->save();
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000319 for (size_t column = 0; column < 4; ++column) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000320 if (0 < column) {
321 canvas->translate(rect.width() + 4*SK_Scalar1, 0);
322 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000323
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000324 SkColor color = 0xff007000;
325 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
326 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
327 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
328 SkPath path;
329 unsigned s1 = (rand.nextU() >> 16) % numSegments;
330 unsigned s2 = (rand.nextU() >> 16) % numSegments;
331 unsigned s3 = (rand.nextU() >> 16) % numSegments;
332 unsigned s4 = (rand.nextU() >> 16) % numSegments;
333 unsigned s5 = (rand.nextU() >> 16) % numSegments;
334 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
335 pt = gSegmentFunctions[s1](path, pt);
336 pt = gSegmentFunctions[s2](path, pt);
337 pt = gSegmentFunctions[s3](path, pt);
338 pt = gSegmentFunctions[s4](path, pt);
339 pt = gSegmentFunctions[s5](path, pt);
340
341 this->drawPath(path, canvas, color, rect,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000342 cap.fCap, cap.fJoin, style.fStyle,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000343 fill.fFill, SK_Scalar1*6);
344
345 SkPaint rectPaint;
346 rectPaint.setColor(SK_ColorBLACK);
347 rectPaint.setStyle(SkPaint::kStroke_Style);
348 rectPaint.setStrokeWidth(-1);
349 rectPaint.setAntiAlias(true);
350 canvas->drawRect(rect, rectPaint);
351
352 SkPaint labelPaint;
353 labelPaint.setColor(color);
354 labelPaint.setAntiAlias(true);
caryclark5fb6bd42014-06-23 11:25:00 -0700355 sk_tool_utils::set_portable_typeface(&labelPaint);
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000356 labelPaint.setLCDRenderText(true);
357 labelPaint.setTextSize(10 * SK_Scalar1);
358 canvas->drawText(style.fName,
359 strlen(style.fName),
360 0, rect.height() + 12 * SK_Scalar1,
361 labelPaint);
362 canvas->drawText(fill.fName,
363 strlen(fill.fName),
364 0, rect.height() + 24 * SK_Scalar1,
365 labelPaint);
366 canvas->drawText(cap.fName,
367 strlen(cap.fName),
368 0, rect.height() + 36 * SK_Scalar1,
369 labelPaint);
370 canvas->drawText(gSegmentNames[s1],
371 strlen(gSegmentNames[s1]),
372 0, rect.height() + 48 * SK_Scalar1,
373 labelPaint);
374 canvas->drawText(gSegmentNames[s2],
375 strlen(gSegmentNames[s2]),
376 0, rect.height() + 60 * SK_Scalar1,
377 labelPaint);
378 canvas->drawText(gSegmentNames[s3],
379 strlen(gSegmentNames[s3]),
380 0, rect.height() + 72 * SK_Scalar1,
381 labelPaint);
382 canvas->drawText(gSegmentNames[s4],
383 strlen(gSegmentNames[s4]),
384 0, rect.height() + 84 * SK_Scalar1,
385 labelPaint);
386 canvas->drawText(gSegmentNames[s5],
387 strlen(gSegmentNames[s5]),
388 0, rect.height() + 96 * SK_Scalar1,
389 labelPaint);
390 }
391 canvas->restore();
392 }
393 canvas->restore();
394 canvas->restore();
395 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000396
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000397private:
398 typedef GM INHERITED;
399};
400
401//////////////////////////////////////////////////////////////////////////////
402
403static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
404static GMRegistry reg(MyFactory);
405
406}