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