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