• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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/SkPaint.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkPathEffect.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkScalar.h"
16 #include "include/core/SkTypes.h"
17 #include "include/effects/SkDashPathEffect.h"
18 #include "include/private/SkFloatBits.h"
19 #include "include/private/SkTArray.h"
20 
21 #include <functional>
22 
23 constexpr SkScalar kStarts[] = {0.f, 10.f, 30.f, 45.f, 90.f, 165.f, 180.f, 270.f};
24 constexpr SkScalar kSweeps[] = {1.f, 45.f, 90.f, 130.f, 180.f, 184.f, 300.f, 355.f};
25 constexpr SkScalar kDiameter = 40.f;
26 constexpr SkRect kRect = {0.f, 0.f, kDiameter, kDiameter};
27 constexpr int kW = 1000;
28 constexpr int kH = 1000;
29 constexpr SkScalar kPad = 20.f;
30 
draw_arcs(SkCanvas * canvas,std::function<void (SkPaint *)> configureStyle)31 void draw_arcs(SkCanvas* canvas, std::function<void(SkPaint*)> configureStyle) {
32     // Draws grid of arcs with different start/sweep angles in red and their complement arcs in
33     // blue.
34     auto drawGrid = [canvas, &configureStyle] (SkScalar x, SkScalar y, bool useCenter, bool aa) {
35         SkPaint p0;
36         p0.setColor(SK_ColorRED);
37         p0.setAntiAlias(aa);
38         // Set a reasonable stroke width that configureStyle can override.
39         p0.setStrokeWidth(15.f);
40         SkPaint p1 = p0;
41         p1.setColor(SK_ColorBLUE);
42         // Use alpha so we see magenta on overlap between arc and its complement.
43         p0.setAlpha(100);
44         p1.setAlpha(100);
45         configureStyle(&p0);
46         configureStyle(&p1);
47 
48         canvas->save();
49         canvas->translate(kPad + x, kPad + y);
50         for (auto start : kStarts) {
51             canvas->save();
52             for (auto sweep : kSweeps) {
53                 canvas->drawArc(kRect, start, sweep, useCenter, p0);
54                 canvas->drawArc(kRect, start, -(360.f - sweep), useCenter, p1);
55                 canvas->translate(kRect.width() + kPad, 0.f);
56             }
57             canvas->restore();
58             canvas->translate(0, kRect.height() + kPad);
59         }
60         canvas->restore();
61     };
62     // Draw a grids for combo of enabling/disabling aa and using center.
63     constexpr SkScalar kGridW = kW / 2.f;
64     constexpr SkScalar kGridH = kH / 2.f;
65     drawGrid(0.f   , 0.f   , false, false);
66     drawGrid(kGridW, 0.f   , true , false);
67     drawGrid(0.f   , kGridH, false, true );
68     drawGrid(kGridW, kGridH, true , true );
69     // Draw separators between the grids.
70     SkPaint linePaint;
71     linePaint.setAntiAlias(true);
72     linePaint.setColor(SK_ColorBLACK);
73     canvas->drawLine(kGridW, 0.f   , kGridW,            SkIntToScalar(kH), linePaint);
74     canvas->drawLine(0.f   , kGridH, SkIntToScalar(kW), kGridH,            linePaint);
75 }
76 
77 #define DEF_ARC_GM(name) DEF_SIMPLE_GM(circular_arcs_##name, canvas, kW, kH)
78 
DEF_ARC_GM(fill)79 DEF_ARC_GM(fill) {
80     auto setFill = [] (SkPaint*p) { p->setStyle(SkPaint::kFill_Style); };
81     draw_arcs(canvas, setFill);
82 }
83 
DEF_ARC_GM(hairline)84 DEF_ARC_GM(hairline) {
85     auto setHairline = [] (SkPaint* p) {
86         p->setStyle(SkPaint::kStroke_Style);
87         p->setStrokeWidth(0.f);
88     };
89     draw_arcs(canvas, setHairline);
90 }
91 
DEF_ARC_GM(stroke_butt)92 DEF_ARC_GM(stroke_butt) {
93     auto setStroke = [](SkPaint* p) {
94         p->setStyle(SkPaint::kStroke_Style);
95         p->setStrokeCap(SkPaint::kButt_Cap);
96     };
97     draw_arcs(canvas, setStroke);
98 }
99 
DEF_ARC_GM(stroke_square)100 DEF_ARC_GM(stroke_square) {
101     auto setStroke = [] (SkPaint* p) {
102         p->setStyle(SkPaint::kStroke_Style);
103         p->setStrokeCap(SkPaint::kSquare_Cap);
104     };
105     draw_arcs(canvas, setStroke);
106 }
107 
DEF_ARC_GM(stroke_round)108 DEF_ARC_GM(stroke_round) {
109     auto setStroke = [] (SkPaint* p) {
110         p->setStyle(SkPaint::kStroke_Style);
111         p->setStrokeCap(SkPaint::kRound_Cap);
112     };
113     draw_arcs(canvas, setStroke);
114 }
115 
DEF_ARC_GM(stroke_and_fill_butt)116 DEF_ARC_GM(stroke_and_fill_butt) {
117     auto setStroke = [] (SkPaint* p) {
118         p->setStyle(SkPaint::kStrokeAndFill_Style);
119         p->setStrokeCap(SkPaint::kButt_Cap);
120     };
121     draw_arcs(canvas, setStroke);
122 }
123 
DEF_ARC_GM(stroke_and_fill_square)124 DEF_ARC_GM(stroke_and_fill_square) {
125     auto setStroke = [] (SkPaint* p) {
126         p->setStyle(SkPaint::kStrokeAndFill_Style);
127         p->setStrokeCap(SkPaint::kSquare_Cap);
128     };
129     draw_arcs(canvas, setStroke);
130 }
131 
DEF_ARC_GM(stroke_and_fill_round)132 DEF_ARC_GM(stroke_and_fill_round) {
133     auto setStroke = [] (SkPaint* p) {
134         p->setStyle(SkPaint::kStrokeAndFill_Style);
135         p->setStrokeCap(SkPaint::kRound_Cap);
136     };
137     draw_arcs(canvas, setStroke);
138 }
139 
140 DEF_SIMPLE_GM(circular_arcs_weird, canvas, 1000, 400) {
141     constexpr SkScalar kS = 50;
142     struct Arc {
143         SkRect   fOval;
144         SkScalar fStart;
145         SkScalar fSweep;
146     };
147     const Arc noDrawArcs[] = {
148         // no sweep
149         {SkRect::MakeWH(kS, kS),  0,  0},
150         // empty rect in x
151         {SkRect::MakeWH(-kS, kS), 0, 90},
152         // empty rect in y
153         {SkRect::MakeWH(kS, -kS), 0, 90},
154         // empty rect in x and y
155         {SkRect::MakeWH( 0,   0), 0, 90},
156     };
157     const Arc arcs[] = {
158         // large start
159         {SkRect::MakeWH(kS, kS),   810.f,   90.f},
160         // large negative start
161         {SkRect::MakeWH(kS, kS),  -810.f,   90.f},
162         // exactly 360 sweep
163         {SkRect::MakeWH(kS, kS),     0.f,  360.f},
164         // exactly -360 sweep
165         {SkRect::MakeWH(kS, kS),     0.f, -360.f},
166         // exactly 540 sweep
167         {SkRect::MakeWH(kS, kS),     0.f,  540.f},
168         // exactly -540 sweep
169         {SkRect::MakeWH(kS, kS),     0.f, -540.f},
170         // generic large sweep and large start
171         {SkRect::MakeWH(kS, kS),  1125.f,  990.f},
172     };
173     SkTArray<SkPaint> paints;
174     // fill
175     paints.push_back();
176     // stroke
177     paints.push_back().setStyle(SkPaint::kStroke_Style);
178     paints.back().setStrokeWidth(kS / 6.f);
179     // hairline
180     paints.push_back().setStyle(SkPaint::kStroke_Style);
181     paints.back().setStrokeWidth(0.f);
182     // stroke and fill
183     paints.push_back().setStyle(SkPaint::kStrokeAndFill_Style);
184     paints.back().setStrokeWidth(kS / 6.f);
185     // dash effect
186     paints.push_back().setStyle(SkPaint::kStroke_Style);
187     paints.back().setStrokeWidth(kS / 6.f);
188     constexpr SkScalar kDashIntervals[] = {kS / 15, 2 * kS / 15};
189     paints.back().setPathEffect(SkDashPathEffect::Make(kDashIntervals, 2, 0.f));
190 
191     canvas->translate(kPad, kPad);
192     // This loop should draw nothing.
193     for (auto arc : noDrawArcs) {
194         for (auto paint : paints) {
195             paint.setAntiAlias(true);
196             canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
197             canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
198         }
199     }
200 
201     SkPaint linePaint;
202     linePaint.setAntiAlias(true);
203     linePaint.setColor(SK_ColorRED);
204     SkScalar midX   = SK_ARRAY_COUNT(arcs) * (kS + kPad) - kPad/2.f;
205     SkScalar height = paints.count() * (kS + kPad);
206     canvas->drawLine(midX, -kPad, midX, height, linePaint);
207 
208     for (auto paint : paints) {
209         paint.setAntiAlias(true);
210         canvas->save();
211         for (auto arc : arcs) {
212             canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
213             canvas->translate(kS + kPad, 0.f);
214         }
215         for (auto arc : arcs) {
216             canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
217             canvas->translate(kS + kPad, 0.f);
218         }
219         canvas->restore();
220         canvas->translate(0, kS + kPad);
221     }
222 }
223 
224 DEF_SIMPLE_GM(onebadarc, canvas, 100, 100) {
225     SkPath path;
226     path.moveTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000));  // 20, 20
227     path.lineTo(SkBits2Float(0x4208918c), SkBits2Float(0x4208918c));  // 34.1421f, 34.1421f
228     path.conicTo(SkBits2Float(0x41a00000), SkBits2Float(0x42412318),  // 20, 48.2843f
229             SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c),       // 5.85786f, 34.1421f
230             SkBits2Float(0x3f3504f3));                                // 0.707107f
231     path.quadTo(SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c),   // 5.85786f, 34.1421f
232             SkBits2Float(0x40bb73a2), SkBits2Float(0x4208918c));      // 5.85787f, 34.1421f
233     path.lineTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000));  // 20, 20
234     path.close();
235     SkPaint p0;
236     p0.setColor(SK_ColorRED);
237     p0.setStrokeWidth(15.f);
238     p0.setStyle(SkPaint::kStroke_Style);
239     p0.setAlpha(100);
240     canvas->translate(20, 0);
241     canvas->drawPath(path, p0);
242 
243     SkRect kRect = { 60, 0, 100, 40};
244     canvas->drawArc(kRect, 45, 90, true, p0);
245 }
246 
247 DEF_SIMPLE_GM(crbug_888453, canvas, 480, 150) {
248     // Two GPU path renderers were using a too-large tolerance when chopping connics to quads.
249     // This manifested as not-very-round circular arcs at certain radii. All the arcs being drawn
250     // here should look like circles.
251     SkPaint fill;
252     fill.setAntiAlias(true);
253     SkPaint hairline = fill;
254     hairline.setStyle(SkPaint::kStroke_Style);
255     SkPaint stroke = hairline;
256     stroke.setStrokeWidth(2.0f);
257     int x = 4;
258     int y0 = 25, y1 = 75, y2 = 125;
259     for (int r = 2; r <= 20; ++r) {
260         canvas->drawArc(SkRect::MakeXYWH(x - r, y0 - r, 2 * r, 2 * r), 0, 360, false, fill);
261         canvas->drawArc(SkRect::MakeXYWH(x - r, y1 - r, 2 * r, 2 * r), 0, 360, false, hairline);
262         canvas->drawArc(SkRect::MakeXYWH(x - r, y2 - r, 2 * r, 2 * r), 0, 360, false, stroke);
263         x += 2 * r + 4;
264     }
265 }
266