blob: 7288d953bf8b3d0977f58cec60bebf5aa3b944b1 [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
29 SkISize onISize() { return make_isize(1368, 1230); }
30
31 typedef SkPoint (*AddSegmentFunc)(SkPath&, SkPoint&);
32
33 // We need to use explicit commands here, instead of addPath, because we
34 // do not want the SkPath::Iter used in addPath to remove the degenerate
35 // segments before we send th epath off for drawing.
36 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,
193 const SkRect& clip, SkPaint::Cap cap,
194 SkPaint::Style style, SkPath::FillType fill,
195 SkScalar strokeWidth) {
196 path.setFillType(fill);
197 SkPaint paint;
198 paint.setStrokeCap(cap);
199 paint.setStrokeWidth(strokeWidth);
200 paint.setColor(color);
201 paint.setStyle(style);
202 canvas->save();
203 canvas->clipRect(clip);
204 canvas->drawPath(path, paint);
205 canvas->restore();
206 }
207
208 virtual void onDraw(SkCanvas* canvas) {
209 static const AddSegmentFunc gSegmentFunctions[] = {
210 AddMove,
211 AddMoveClose,
212 AddDegenLine,
213 AddMoveDegenLine,
214 AddMoveDegenLineClose,
215 AddDegenQuad,
216 AddMoveDegenQuad,
217 AddMoveDegenQuadClose,
218 AddDegenCubic,
219 AddMoveDegenCubic,
220 AddMoveDegenCubicClose,
221 AddClose,
222 AddLine,
223 AddMoveLine,
224 AddMoveLineClose,
225 AddQuad,
226 AddMoveQuad,
227 AddMoveQuadClose,
228 AddCubic,
229 AddMoveCubic,
230 AddMoveCubicClose
231 };
232 static const char* gSegmentNames[] = {
233 "Move",
234 "MoveClose",
235 "DegenLine",
236 "MoveDegenLine",
237 "MoveDegenLineClose",
238 "DegenQuad",
239 "MoveDegenQuad",
240 "MoveDegenQuadClose",
241 "DegenCubic",
242 "MoveDegenCubic",
243 "MoveDegenCubicClose",
244 "Close",
245 "Line",
246 "MoveLine",
247 "MoveLineClose",
248 "Quad",
249 "MoveQuad",
250 "MoveQuadClose",
251 "Cubic",
252 "MoveCubic",
253 "MoveCubicClose"
254 };
255
256 struct FillAndName {
257 SkPath::FillType fFill;
258 const char* fName;
259 };
260 static const FillAndName gFills[] = {
261 {SkPath::kWinding_FillType, "Winding"},
262 {SkPath::kEvenOdd_FillType, "Even / Odd"},
263 {SkPath::kInverseWinding_FillType, "Inverse Winding"},
264 {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"}
265 };
266 struct StyleAndName {
267 SkPaint::Style fStyle;
268 const char* fName;
269 };
270 static const StyleAndName gStyles[] = {
271 {SkPaint::kFill_Style, "Fill"},
272 {SkPaint::kStroke_Style, "Stroke 10"},
273 {SkPaint::kStrokeAndFill_Style, "Stroke 10 And Fill"}
274 };
275 struct CapAndName {
276 SkPaint::Cap fCap;
277 const char* fName;
278 };
279 static const CapAndName gCaps[] = {
280 {SkPaint::kButt_Cap, "Butt"},
281 {SkPaint::kRound_Cap, "Round"},
282 {SkPaint::kSquare_Cap, "Square"}
283 };
284
285 SkPaint titlePaint;
286 titlePaint.setColor(SK_ColorBLACK);
287 titlePaint.setAntiAlias(true);
288 titlePaint.setLCDRenderText(true);
289 titlePaint.setTextSize(15 * SK_Scalar1);
290 const char title[] = "Random Paths Drawn Into Rectangle Clips With "
291 "Indicated Style, Fill and Linecaps, "
292 "with Stroke width 6";
293 canvas->drawText(title, strlen(title),
294 20 * SK_Scalar1,
295 20 * SK_Scalar1,
296 titlePaint);
297
298 SkRandom rand;
299 SkRect rect = SkRect::MakeWH(220*SK_Scalar1, 50*SK_Scalar1);
300 canvas->save();
301 canvas->translate(2*SK_Scalar1, 30 * SK_Scalar1); // The title
302 canvas->save();
303 unsigned numSegments = SK_ARRAY_COUNT(gSegmentFunctions);
304 unsigned numCaps = SK_ARRAY_COUNT(gCaps);
305 unsigned numStyles = SK_ARRAY_COUNT(gStyles);
306 unsigned numFills = SK_ARRAY_COUNT(gFills);
307 for (size_t row = 0; row < 8; ++row) {
308 if (0 < row) {
309 canvas->translate(0, rect.height() + 100*SK_Scalar1);
310 }
311 canvas->save();
312 for (size_t column = 0; column < 6; ++column) {
313 if (0 < column) {
314 canvas->translate(rect.width() + 4*SK_Scalar1, 0);
315 }
316
317 SkColor color = 0xff007000;
318 StyleAndName style = gStyles[(rand.nextU() >> 16) % numStyles];
319 CapAndName cap = gCaps[(rand.nextU() >> 16) % numCaps];
320 FillAndName fill = gFills[(rand.nextU() >> 16) % numFills];
321 SkPath path;
322 unsigned s1 = (rand.nextU() >> 16) % numSegments;
323 unsigned s2 = (rand.nextU() >> 16) % numSegments;
324 unsigned s3 = (rand.nextU() >> 16) % numSegments;
325 unsigned s4 = (rand.nextU() >> 16) % numSegments;
326 unsigned s5 = (rand.nextU() >> 16) % numSegments;
327 SkPoint pt = SkPoint::Make(10*SK_Scalar1, 0);
328 pt = gSegmentFunctions[s1](path, pt);
329 pt = gSegmentFunctions[s2](path, pt);
330 pt = gSegmentFunctions[s3](path, pt);
331 pt = gSegmentFunctions[s4](path, pt);
332 pt = gSegmentFunctions[s5](path, pt);
333
334 this->drawPath(path, canvas, color, rect,
335 cap.fCap, style.fStyle,
336 fill.fFill, SK_Scalar1*6);
337
338 SkPaint rectPaint;
339 rectPaint.setColor(SK_ColorBLACK);
340 rectPaint.setStyle(SkPaint::kStroke_Style);
341 rectPaint.setStrokeWidth(-1);
342 rectPaint.setAntiAlias(true);
343 canvas->drawRect(rect, rectPaint);
344
345 SkPaint labelPaint;
346 labelPaint.setColor(color);
347 labelPaint.setAntiAlias(true);
348 labelPaint.setLCDRenderText(true);
349 labelPaint.setTextSize(10 * SK_Scalar1);
350 canvas->drawText(style.fName,
351 strlen(style.fName),
352 0, rect.height() + 12 * SK_Scalar1,
353 labelPaint);
354 canvas->drawText(fill.fName,
355 strlen(fill.fName),
356 0, rect.height() + 24 * SK_Scalar1,
357 labelPaint);
358 canvas->drawText(cap.fName,
359 strlen(cap.fName),
360 0, rect.height() + 36 * SK_Scalar1,
361 labelPaint);
362 canvas->drawText(gSegmentNames[s1],
363 strlen(gSegmentNames[s1]),
364 0, rect.height() + 48 * SK_Scalar1,
365 labelPaint);
366 canvas->drawText(gSegmentNames[s2],
367 strlen(gSegmentNames[s2]),
368 0, rect.height() + 60 * SK_Scalar1,
369 labelPaint);
370 canvas->drawText(gSegmentNames[s3],
371 strlen(gSegmentNames[s3]),
372 0, rect.height() + 72 * SK_Scalar1,
373 labelPaint);
374 canvas->drawText(gSegmentNames[s4],
375 strlen(gSegmentNames[s4]),
376 0, rect.height() + 84 * SK_Scalar1,
377 labelPaint);
378 canvas->drawText(gSegmentNames[s5],
379 strlen(gSegmentNames[s5]),
380 0, rect.height() + 96 * SK_Scalar1,
381 labelPaint);
382 }
383 canvas->restore();
384 }
385 canvas->restore();
386 canvas->restore();
387 }
388
389private:
390 typedef GM INHERITED;
391};
392
393//////////////////////////////////////////////////////////////////////////////
394
395static GM* MyFactory(void*) { return new DegenerateSegmentsGM; }
396static GMRegistry reg(MyFactory);
397
398}