blob: 63d9dba651ad07aa70ddb4921a426a885f3062c3 [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 }
28
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +000029 SkISize onISize() { return make_isize(896, 930); }
schenney@chromium.org4da06ab2011-12-20 15:14:18 +000030
31 typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
32
33 // 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 }
208
209 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);
290 titlePaint.setLCDRenderText(true);
291 titlePaint.setTextSize(15 * SK_Scalar1);
292 const char title[] = "Random Paths Drawn Into Rectangle Clips With "
293 "Indicated Style, Fill and Linecaps, "
294 "with Stroke width 6";
295 canvas->drawText(title, strlen(title),
296 20 * SK_Scalar1,
297 20 * SK_Scalar1,
298 titlePaint);
299
300 SkRandom rand;
301 SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
302 canvas->save();
303 canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
304 canvas->save();
305 unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
306 unsigned numCaps = SK_ARRAY_COUNT(gCaps);
307 unsigned numStyles = SK_ARRAY_COUNT(gStyles);
308 unsigned numFills = SK_ARRAY_COUNT(gFills);
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000309 for (size_t row = 0; row < 6; ++row) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000310 if (0 < row) {
311 canvas->translate(0, rect.height() + 100*SK_Scalar1);
312 }
313 canvas->save();
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000314 for (size_t column = 0; column < 4; ++column) {
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000315 if (0 < column) {
316 canvas->translate(rect.width() + 4*SK_Scalar1, 0);
317 }
318
319 SkColor color = 0xff007000;
320 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
321 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
322 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
323 SkPath path;
324 unsigned s1 = (rand.nextU() >> 16) % numSegments;
325 unsigned s2 = (rand.nextU() >> 16) % numSegments;
326 unsigned s3 = (rand.nextU() >> 16) % numSegments;
327 unsigned s4 = (rand.nextU() >> 16) % numSegments;
328 unsigned s5 = (rand.nextU() >> 16) % numSegments;
329 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
330 pt = gSegmentFunctions[s1](path, pt);
331 pt = gSegmentFunctions[s2](path, pt);
332 pt = gSegmentFunctions[s3](path, pt);
333 pt = gSegmentFunctions[s4](path, pt);
334 pt = gSegmentFunctions[s5](path, pt);
335
336 this->drawPath(path, canvas, color, rect,
schenney@chromium.org45cbfdd2011-12-20 21:48:14 +0000337 cap.fCap, cap.fJoin, style.fStyle,
schenney@chromium.org4da06ab2011-12-20 15:14:18 +0000338 fill.fFill, SK_Scalar1*6);
339
340 SkPaint rectPaint;
341 rectPaint.setColor(SK_ColorBLACK);
342 rectPaint.setStyle(SkPaint::kStroke_Style);
343 rectPaint.setStrokeWidth(-1);
344 rectPaint.setAntiAlias(true);
345 canvas->drawRect(rect, rectPaint);
346
347 SkPaint labelPaint;
348 labelPaint.setColor(color);
349 labelPaint.setAntiAlias(true);
350 labelPaint.setLCDRenderText(true);
351 labelPaint.setTextSize(10 * SK_Scalar1);
352 canvas->drawText(style.fName,
353 strlen(style.fName),
354 0, rect.height() + 12 * SK_Scalar1,
355 labelPaint);
356 canvas->drawText(fill.fName,
357 strlen(fill.fName),
358 0, rect.height() + 24 * SK_Scalar1,
359 labelPaint);
360 canvas->drawText(cap.fName,
361 strlen(cap.fName),
362 0, rect.height() + 36 * SK_Scalar1,
363 labelPaint);
364 canvas->drawText(gSegmentNames[s1],
365 strlen(gSegmentNames[s1]),
366 0, rect.height() + 48 * SK_Scalar1,
367 labelPaint);
368 canvas->drawText(gSegmentNames[s2],
369 strlen(gSegmentNames[s2]),
370 0, rect.height() + 60 * SK_Scalar1,
371 labelPaint);
372 canvas->drawText(gSegmentNames[s3],
373 strlen(gSegmentNames[s3]),
374 0, rect.height() + 72 * SK_Scalar1,
375 labelPaint);
376 canvas->drawText(gSegmentNames[s4],
377 strlen(gSegmentNames[s4]),
378 0, rect.height() + 84 * SK_Scalar1,
379 labelPaint);
380 canvas->drawText(gSegmentNames[s5],
381 strlen(gSegmentNames[s5]),
382 0, rect.height() + 96 * SK_Scalar1,
383 labelPaint);
384 }
385 canvas->restore();
386 }
387 canvas->restore();
388 canvas->restore();
389 }
390
391private:
392 typedef GM INHERITED;
393};
394
395//////////////////////////////////////////////////////////////////////////////
396
397static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
398static GMRegistry reg(MyFactory);
399
400}