• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #include "gm.h"
9 #include "sk_tool_utils.h"
10 #include "SkCanvas.h"
11 #include "SkPaint.h"
12 #include "SkPath.h"
13 #include "SkRandom.h"
14 
15 // https://bug.skia.org/1316 shows that this cubic, when slightly clipped, creates big
16 // (incorrect) changes to its control points.
17 class ClippedCubicGM : public skiagm::GM {
18 public:
ClippedCubicGM()19     ClippedCubicGM() {}
20 
21 protected:
22 
onShortName()23     SkString onShortName() {
24         return SkString("clippedcubic");
25     }
26 
onISize()27     SkISize onISize() { return SkISize::Make(1240, 390); }
28 
onDraw(SkCanvas * canvas)29     virtual void onDraw(SkCanvas* canvas) {
30         SkPath path;
31         path.moveTo(0, 0);
32         path.cubicTo(140, 150, 40, 10, 170, 150);
33 
34         SkPaint paint;
35         SkRect bounds = path.getBounds();
36 
37         for (SkScalar dy = -1; dy <= 1; dy += 1) {
38             canvas->save();
39             for (SkScalar dx = -1; dx <= 1; dx += 1) {
40                 canvas->save();
41                 canvas->clipRect(bounds);
42                 canvas->translate(dx, dy);
43                 canvas->drawPath(path, paint);
44                 canvas->restore();
45 
46                 canvas->translate(bounds.width(), 0);
47             }
48             canvas->restore();
49             canvas->translate(0, bounds.height());
50         }
51     }
52 
53 private:
54     typedef skiagm::GM INHERITED;
55 };
56 
57 
58 class ClippedCubic2GM : public skiagm::GM {
59 public:
ClippedCubic2GM()60     ClippedCubic2GM() {}
61 
62 protected:
63 
onShortName()64     SkString onShortName() override {
65         return SkString("clippedcubic2");
66     }
67 
onISize()68     SkISize onISize() override { return SkISize::Make(1240, 390); }
69 
onDraw(SkCanvas * canvas)70     void onDraw(SkCanvas* canvas) override {
71         canvas->save();
72         canvas->translate(-2, 120);
73         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 150));
74         canvas->translate(0, 170);
75         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 80, 100));
76         canvas->translate(0, 170);
77         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 30, 150));
78         canvas->translate(0, 170);
79         drawOne(canvas, fPath, SkRect::MakeLTRB(0, 0, 10, 150));
80         canvas->restore();
81         canvas->save();
82         canvas->translate(20, -2);
83         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 80));
84         canvas->translate(170, 0);
85         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 100, 80));
86         canvas->translate(170, 0);
87         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 30));
88         canvas->translate(170, 0);
89         drawOne(canvas, fFlipped, SkRect::MakeLTRB(0, 0, 150, 10));
90         canvas->restore();
91     }
92 
drawOne(SkCanvas * canvas,const SkPath & path,const SkRect & clip)93     void drawOne(SkCanvas* canvas, const SkPath& path, const SkRect& clip) {
94         SkPaint framePaint, fillPaint;
95         framePaint.setStyle(SkPaint::kStroke_Style);
96         canvas->drawRect(clip, framePaint);
97         canvas->drawPath(path, framePaint);
98         canvas->save();
99         canvas->clipRect(clip);
100         canvas->drawPath(path, fillPaint);
101         canvas->restore();
102     }
103 
onOnceBeforeDraw()104     void onOnceBeforeDraw() override {
105         fPath.moveTo(69.7030518991886f, 0);
106         fPath.cubicTo( 69.7030518991886f, 21.831149999999997f,
107                 58.08369508178456f, 43.66448333333333f, 34.8449814469765f, 65.5f);
108         fPath.cubicTo( 11.608591683531916f, 87.33115f, -0.010765133872116195f, 109.16448333333332f,
109                 -0.013089005235602302f, 131);
110         fPath.close();
111         fFlipped = fPath;
112         SkMatrix matrix;
113         matrix.reset();
114         matrix.setScaleX(0);
115         matrix.setScaleY(0);
116         matrix.setSkewX(1);
117         matrix.setSkewY(1);
118         fFlipped.transform(matrix);
119     }
120 
121     SkPath fPath;
122     SkPath fFlipped;
123 private:
124     typedef skiagm::GM INHERITED;
125 };
126 
127 
128 class CubicPathGM : public skiagm::GM {
129 public:
CubicPathGM()130     CubicPathGM() {}
131 
132 protected:
133 
onShortName()134     SkString onShortName() {
135         return SkString("cubicpath");
136     }
137 
onISize()138     SkISize onISize() { return SkISize::Make(1240, 390); }
139 
drawPath(SkPath & path,SkCanvas * canvas,SkColor color,const SkRect & clip,SkPaint::Cap cap,SkPaint::Join join,SkPaint::Style style,SkPath::FillType fill,SkScalar strokeWidth)140     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
141                   const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
142                   SkPaint::Style style, SkPath::FillType fill,
143                   SkScalar strokeWidth) {
144         path.setFillType(fill);
145         SkPaint paint;
146         paint.setStrokeCap(cap);
147         paint.setStrokeWidth(strokeWidth);
148         paint.setStrokeJoin(join);
149         paint.setColor(color);
150         paint.setStyle(style);
151         canvas->save();
152         canvas->clipRect(clip);
153         canvas->drawPath(path, paint);
154         canvas->restore();
155     }
156 
onDraw(SkCanvas * canvas)157     virtual void onDraw(SkCanvas* canvas) {
158         struct FillAndName {
159             SkPath::FillType fFill;
160             const char*      fName;
161         };
162         constexpr FillAndName gFills[] = {
163             {SkPath::kWinding_FillType, "Winding"},
164             {SkPath::kEvenOdd_FillType, "Even / Odd"},
165             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
166             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
167         };
168         struct StyleAndName {
169             SkPaint::Style fStyle;
170             const char*    fName;
171         };
172         constexpr StyleAndName gStyles[] = {
173             {SkPaint::kFill_Style, "Fill"},
174             {SkPaint::kStroke_Style, "Stroke"},
175             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
176         };
177         struct CapAndName {
178             SkPaint::Cap  fCap;
179             SkPaint::Join fJoin;
180             const char*   fName;
181         };
182         constexpr CapAndName gCaps[] = {
183             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
184             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
185             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
186         };
187         struct PathAndName {
188             SkPath      fPath;
189             const char* fName;
190         };
191         PathAndName path;
192         path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
193         path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
194                            60*SK_Scalar1, 20*SK_Scalar1,
195                            75*SK_Scalar1, 10*SK_Scalar1);
196         path.fName = "moveTo-cubic";
197 
198         SkPaint titlePaint;
199         titlePaint.setColor(SK_ColorBLACK);
200         titlePaint.setAntiAlias(true);
201         sk_tool_utils::set_portable_typeface(&titlePaint);
202         titlePaint.setTextSize(15 * SK_Scalar1);
203         const char title[] = "Cubic Drawn Into Rectangle Clips With "
204                              "Indicated Style, Fill and Linecaps, with stroke width 10";
205         canvas->drawText(title, strlen(title),
206                             20 * SK_Scalar1,
207                             20 * SK_Scalar1,
208                             titlePaint);
209 
210         SkRandom rand;
211         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
212         canvas->save();
213         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
214         canvas->save();
215         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
216             if (0 < cap) {
217                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
218             }
219             canvas->save();
220             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
221                 if (0 < fill) {
222                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
223                 }
224                 canvas->save();
225                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
226                     if (0 < style) {
227                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
228                     }
229 
230                     SkColor color = 0xff007000;
231                     this->drawPath(path.fPath, canvas, color, rect,
232                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
233                                     gFills[fill].fFill, SK_Scalar1*10);
234 
235                     SkPaint rectPaint;
236                     rectPaint.setColor(SK_ColorBLACK);
237                     rectPaint.setStyle(SkPaint::kStroke_Style);
238                     rectPaint.setStrokeWidth(-1);
239                     rectPaint.setAntiAlias(true);
240                     canvas->drawRect(rect, rectPaint);
241 
242                     SkPaint labelPaint;
243                     labelPaint.setColor(color);
244                     labelPaint.setAntiAlias(true);
245                     sk_tool_utils::set_portable_typeface(&labelPaint);
246                     labelPaint.setTextSize(10 * SK_Scalar1);
247                     canvas->drawText(gStyles[style].fName,
248                                         strlen(gStyles[style].fName),
249                                         0, rect.height() + 12 * SK_Scalar1,
250                                         labelPaint);
251                     canvas->drawText(gFills[fill].fName,
252                                         strlen(gFills[fill].fName),
253                                         0, rect.height() + 24 * SK_Scalar1,
254                                         labelPaint);
255                     canvas->drawText(gCaps[cap].fName,
256                                         strlen(gCaps[cap].fName),
257                                         0, rect.height() + 36 * SK_Scalar1,
258                                         labelPaint);
259                 }
260                 canvas->restore();
261             }
262             canvas->restore();
263         }
264         canvas->restore();
265         canvas->restore();
266     }
267 
268 private:
269     typedef skiagm::GM INHERITED;
270 };
271 
272 class CubicClosePathGM : public skiagm::GM {
273 public:
CubicClosePathGM()274     CubicClosePathGM() {}
275 
276 protected:
277 
onShortName()278     SkString onShortName() {
279         return SkString("cubicclosepath");
280     }
281 
onISize()282     SkISize onISize() { return SkISize::Make(1240, 390); }
283 
drawPath(SkPath & path,SkCanvas * canvas,SkColor color,const SkRect & clip,SkPaint::Cap cap,SkPaint::Join join,SkPaint::Style style,SkPath::FillType fill,SkScalar strokeWidth)284     void drawPath(SkPath& path,SkCanvas* canvas,SkColor color,
285                   const SkRect& clip,SkPaint::Cap cap, SkPaint::Join join,
286                   SkPaint::Style style, SkPath::FillType fill,
287                   SkScalar strokeWidth) {
288         path.setFillType(fill);
289         SkPaint paint;
290         paint.setStrokeCap(cap);
291         paint.setStrokeWidth(strokeWidth);
292         paint.setStrokeJoin(join);
293         paint.setColor(color);
294         paint.setStyle(style);
295         canvas->save();
296         canvas->clipRect(clip);
297         canvas->drawPath(path, paint);
298         canvas->restore();
299     }
300 
onDraw(SkCanvas * canvas)301     virtual void onDraw(SkCanvas* canvas) {
302         struct FillAndName {
303             SkPath::FillType fFill;
304             const char*      fName;
305         };
306         constexpr FillAndName gFills[] = {
307             {SkPath::kWinding_FillType, "Winding"},
308             {SkPath::kEvenOdd_FillType, "Even / Odd"},
309             {SkPath::kInverseWinding_FillType, "Inverse Winding"},
310             {SkPath::kInverseEvenOdd_FillType, "Inverse Even / Odd"},
311         };
312         struct StyleAndName {
313             SkPaint::Style fStyle;
314             const char*    fName;
315         };
316         constexpr StyleAndName gStyles[] = {
317             {SkPaint::kFill_Style, "Fill"},
318             {SkPaint::kStroke_Style, "Stroke"},
319             {SkPaint::kStrokeAndFill_Style, "Stroke And Fill"},
320         };
321         struct CapAndName {
322             SkPaint::Cap  fCap;
323             SkPaint::Join fJoin;
324             const char*   fName;
325         };
326         constexpr CapAndName gCaps[] = {
327             {SkPaint::kButt_Cap, SkPaint::kBevel_Join, "Butt"},
328             {SkPaint::kRound_Cap, SkPaint::kRound_Join, "Round"},
329             {SkPaint::kSquare_Cap, SkPaint::kBevel_Join, "Square"}
330         };
331         struct PathAndName {
332             SkPath      fPath;
333             const char* fName;
334         };
335         PathAndName path;
336         path.fPath.moveTo(25*SK_Scalar1, 10*SK_Scalar1);
337         path.fPath.cubicTo(40*SK_Scalar1, 20*SK_Scalar1,
338                            60*SK_Scalar1, 20*SK_Scalar1,
339                            75*SK_Scalar1, 10*SK_Scalar1);
340         path.fPath.close();
341         path.fName = "moveTo-cubic-close";
342 
343         SkPaint titlePaint;
344         titlePaint.setColor(SK_ColorBLACK);
345         titlePaint.setAntiAlias(true);
346         sk_tool_utils::set_portable_typeface(&titlePaint);
347         titlePaint.setTextSize(15 * SK_Scalar1);
348         const char title[] = "Cubic Closed Drawn Into Rectangle Clips With "
349                              "Indicated Style, Fill and Linecaps, with stroke width 10";
350         canvas->drawText(title, strlen(title),
351                             20 * SK_Scalar1,
352                             20 * SK_Scalar1,
353                             titlePaint);
354 
355         SkRandom rand;
356         SkRect rect = SkRect::MakeWH(100*SK_Scalar1, 30*SK_Scalar1);
357         canvas->save();
358         canvas->translate(10 * SK_Scalar1, 30 * SK_Scalar1);
359         canvas->save();
360         for (size_t cap = 0; cap < SK_ARRAY_COUNT(gCaps); ++cap) {
361             if (0 < cap) {
362                 canvas->translate((rect.width() + 40 * SK_Scalar1) * SK_ARRAY_COUNT(gStyles), 0);
363             }
364             canvas->save();
365             for (size_t fill = 0; fill < SK_ARRAY_COUNT(gFills); ++fill) {
366                 if (0 < fill) {
367                     canvas->translate(0, rect.height() + 40 * SK_Scalar1);
368                 }
369                 canvas->save();
370                 for (size_t style = 0; style < SK_ARRAY_COUNT(gStyles); ++style) {
371                     if (0 < style) {
372                         canvas->translate(rect.width() + 40 * SK_Scalar1, 0);
373                     }
374 
375                     SkColor color = 0xff007000;
376                     this->drawPath(path.fPath, canvas, color, rect,
377                                     gCaps[cap].fCap, gCaps[cap].fJoin, gStyles[style].fStyle,
378                                     gFills[fill].fFill, SK_Scalar1*10);
379 
380                     SkPaint rectPaint;
381                     rectPaint.setColor(SK_ColorBLACK);
382                     rectPaint.setStyle(SkPaint::kStroke_Style);
383                     rectPaint.setStrokeWidth(-1);
384                     rectPaint.setAntiAlias(true);
385                     canvas->drawRect(rect, rectPaint);
386 
387                     SkPaint labelPaint;
388                     labelPaint.setColor(color);
389                     labelPaint.setAntiAlias(true);
390                     sk_tool_utils::set_portable_typeface(&labelPaint);
391                     labelPaint.setTextSize(10 * SK_Scalar1);
392                     canvas->drawText(gStyles[style].fName,
393                                         strlen(gStyles[style].fName),
394                                         0, rect.height() + 12 * SK_Scalar1,
395                                         labelPaint);
396                     canvas->drawText(gFills[fill].fName,
397                                         strlen(gFills[fill].fName),
398                                         0, rect.height() + 24 * SK_Scalar1,
399                                         labelPaint);
400                     canvas->drawText(gCaps[cap].fName,
401                                         strlen(gCaps[cap].fName),
402                                         0, rect.height() + 36 * SK_Scalar1,
403                                         labelPaint);
404                 }
405                 canvas->restore();
406             }
407             canvas->restore();
408         }
409         canvas->restore();
410         canvas->restore();
411     }
412 
413 private:
414     typedef skiagm::GM INHERITED;
415 };
416 
417 DEF_SIMPLE_GM(bug5099, canvas, 50, 50) {
418     SkPaint p;
419     p.setColor(SK_ColorRED);
420     p.setAntiAlias(true);
421     p.setStyle(SkPaint::kStroke_Style);
422     p.setStrokeWidth(10);
423 
424     SkPath path;
425     path.moveTo(6, 27);
426     path.cubicTo(31.5f, 1.5f, 3.5f, 4.5f, 29, 29);
427     canvas->drawPath(path, p);
428 }
429 
430 DEF_SIMPLE_GM(bug6083, canvas, 100, 50) {
431     SkPaint p;
432     p.setColor(SK_ColorRED);
433     p.setAntiAlias(true);
434     p.setStyle(SkPaint::kStroke_Style);
435     p.setStrokeWidth(15);
436     canvas->translate(-500, -130);
437     SkPath path;
438     path.moveTo(500.988f, 155.200f);
439     path.lineTo(526.109f, 155.200f);
440     SkPoint p1 = { 526.109f, 155.200f };
441     SkPoint p2 = { 525.968f, 212.968f };
442     SkPoint p3 = { 526.109f, 241.840f };
443     path.cubicTo(p1, p2, p3);
444     canvas->drawPath(path, p);
445     canvas->translate(50, 0);
446     path.reset();
447     p2.set(525.968f, 213.172f);
448     path.moveTo(500.988f, 155.200f);
449     path.lineTo(526.109f, 155.200f);
450     path.cubicTo(p1, p2, p3);
451     canvas->drawPath(path, p);
452 }
453 
454 //////////////////////////////////////////////////////////////////////////////
455 
456 DEF_GM( return new CubicPathGM; )
457 DEF_GM( return new CubicClosePathGM; )
458 DEF_GM( return new ClippedCubicGM; )
459 DEF_GM( return new ClippedCubic2GM; )
460