1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2016 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathBuilder.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkDashPathEffect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkFloatBits.h"
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
24*c8dee2aaSAndroid Build Coastguard Worker
25*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kStarts[] = {0.f, 10.f, 30.f, 45.f, 90.f, 165.f, 180.f, 270.f};
26*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kSweeps[] = {1.f, 45.f, 90.f, 130.f, 180.f, 184.f, 300.f, 355.f};
27*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kDiameter = 40.f;
28*c8dee2aaSAndroid Build Coastguard Worker constexpr SkRect kRect = {0.f, 0.f, kDiameter, kDiameter};
29*c8dee2aaSAndroid Build Coastguard Worker constexpr int kW = 1000;
30*c8dee2aaSAndroid Build Coastguard Worker constexpr int kH = 1000;
31*c8dee2aaSAndroid Build Coastguard Worker
draw_arcs(SkCanvas * canvas,std::function<void (SkPaint *)> configureStyle)32*c8dee2aaSAndroid Build Coastguard Worker void draw_arcs(SkCanvas* canvas, std::function<void(SkPaint*)> configureStyle) {
33*c8dee2aaSAndroid Build Coastguard Worker // Draws grid of arcs with different start/sweep angles in red and their complement arcs in
34*c8dee2aaSAndroid Build Coastguard Worker // blue.
35*c8dee2aaSAndroid Build Coastguard Worker auto drawGrid = [canvas, &configureStyle] (SkScalar x, SkScalar y, bool useCenter, bool aa) {
36*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kPad = 20.f;
37*c8dee2aaSAndroid Build Coastguard Worker SkPaint p0;
38*c8dee2aaSAndroid Build Coastguard Worker p0.setColor(SK_ColorRED);
39*c8dee2aaSAndroid Build Coastguard Worker p0.setAntiAlias(aa);
40*c8dee2aaSAndroid Build Coastguard Worker // Set a reasonable stroke width that configureStyle can override.
41*c8dee2aaSAndroid Build Coastguard Worker p0.setStrokeWidth(15.f);
42*c8dee2aaSAndroid Build Coastguard Worker SkPaint p1 = p0;
43*c8dee2aaSAndroid Build Coastguard Worker p1.setColor(SK_ColorBLUE);
44*c8dee2aaSAndroid Build Coastguard Worker // Use alpha so we see magenta on overlap between arc and its complement.
45*c8dee2aaSAndroid Build Coastguard Worker p0.setAlpha(100);
46*c8dee2aaSAndroid Build Coastguard Worker p1.setAlpha(100);
47*c8dee2aaSAndroid Build Coastguard Worker configureStyle(&p0);
48*c8dee2aaSAndroid Build Coastguard Worker configureStyle(&p1);
49*c8dee2aaSAndroid Build Coastguard Worker
50*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
51*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kPad + x, kPad + y);
52*c8dee2aaSAndroid Build Coastguard Worker for (auto start : kStarts) {
53*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
54*c8dee2aaSAndroid Build Coastguard Worker for (auto sweep : kSweeps) {
55*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(kRect, start, sweep, useCenter, p0);
56*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(kRect, start, -(360.f - sweep), useCenter, p1);
57*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kRect.width() + kPad, 0.f);
58*c8dee2aaSAndroid Build Coastguard Worker }
59*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
60*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, kRect.height() + kPad);
61*c8dee2aaSAndroid Build Coastguard Worker }
62*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
63*c8dee2aaSAndroid Build Coastguard Worker };
64*c8dee2aaSAndroid Build Coastguard Worker // Draw a grids for combo of enabling/disabling aa and using center.
65*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kGridW = kW / 2.f;
66*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kGridH = kH / 2.f;
67*c8dee2aaSAndroid Build Coastguard Worker drawGrid(0.f , 0.f , false, false);
68*c8dee2aaSAndroid Build Coastguard Worker drawGrid(kGridW, 0.f , true , false);
69*c8dee2aaSAndroid Build Coastguard Worker drawGrid(0.f , kGridH, false, true );
70*c8dee2aaSAndroid Build Coastguard Worker drawGrid(kGridW, kGridH, true , true );
71*c8dee2aaSAndroid Build Coastguard Worker // Draw separators between the grids.
72*c8dee2aaSAndroid Build Coastguard Worker SkPaint linePaint;
73*c8dee2aaSAndroid Build Coastguard Worker linePaint.setAntiAlias(true);
74*c8dee2aaSAndroid Build Coastguard Worker linePaint.setColor(SK_ColorBLACK);
75*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(kGridW, 0.f , kGridW, SkIntToScalar(kH), linePaint);
76*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(0.f , kGridH, SkIntToScalar(kW), kGridH, linePaint);
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker #define DEF_ARC_GM(name) DEF_SIMPLE_GM(circular_arcs_##name, canvas, kW, kH)
80*c8dee2aaSAndroid Build Coastguard Worker
DEF_ARC_GM(fill)81*c8dee2aaSAndroid Build Coastguard Worker DEF_ARC_GM(fill) {
82*c8dee2aaSAndroid Build Coastguard Worker auto setFill = [] (SkPaint*p) { p->setStroke(false); };
83*c8dee2aaSAndroid Build Coastguard Worker draw_arcs(canvas, setFill);
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker
DEF_ARC_GM(hairline)86*c8dee2aaSAndroid Build Coastguard Worker DEF_ARC_GM(hairline) {
87*c8dee2aaSAndroid Build Coastguard Worker auto setHairline = [] (SkPaint* p) {
88*c8dee2aaSAndroid Build Coastguard Worker p->setStroke(true);
89*c8dee2aaSAndroid Build Coastguard Worker p->setStrokeWidth(0.f);
90*c8dee2aaSAndroid Build Coastguard Worker };
91*c8dee2aaSAndroid Build Coastguard Worker draw_arcs(canvas, setHairline);
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker
DEF_ARC_GM(stroke_butt)94*c8dee2aaSAndroid Build Coastguard Worker DEF_ARC_GM(stroke_butt) {
95*c8dee2aaSAndroid Build Coastguard Worker auto setStroke = [](SkPaint* p) {
96*c8dee2aaSAndroid Build Coastguard Worker p->setStroke(true);
97*c8dee2aaSAndroid Build Coastguard Worker p->setStrokeCap(SkPaint::kButt_Cap);
98*c8dee2aaSAndroid Build Coastguard Worker };
99*c8dee2aaSAndroid Build Coastguard Worker draw_arcs(canvas, setStroke);
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker
DEF_ARC_GM(stroke_square)102*c8dee2aaSAndroid Build Coastguard Worker DEF_ARC_GM(stroke_square) {
103*c8dee2aaSAndroid Build Coastguard Worker auto setStroke = [] (SkPaint* p) {
104*c8dee2aaSAndroid Build Coastguard Worker p->setStroke(true);
105*c8dee2aaSAndroid Build Coastguard Worker p->setStrokeCap(SkPaint::kSquare_Cap);
106*c8dee2aaSAndroid Build Coastguard Worker };
107*c8dee2aaSAndroid Build Coastguard Worker draw_arcs(canvas, setStroke);
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker
DEF_ARC_GM(stroke_round)110*c8dee2aaSAndroid Build Coastguard Worker DEF_ARC_GM(stroke_round) {
111*c8dee2aaSAndroid Build Coastguard Worker auto setStroke = [] (SkPaint* p) {
112*c8dee2aaSAndroid Build Coastguard Worker p->setStroke(true);
113*c8dee2aaSAndroid Build Coastguard Worker p->setStrokeCap(SkPaint::kRound_Cap);
114*c8dee2aaSAndroid Build Coastguard Worker };
115*c8dee2aaSAndroid Build Coastguard Worker draw_arcs(canvas, setStroke);
116*c8dee2aaSAndroid Build Coastguard Worker }
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(circular_arcs_weird, canvas, 1000, 400) {
119*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kS = 50;
120*c8dee2aaSAndroid Build Coastguard Worker struct Arc {
121*c8dee2aaSAndroid Build Coastguard Worker SkRect fOval;
122*c8dee2aaSAndroid Build Coastguard Worker SkScalar fStart;
123*c8dee2aaSAndroid Build Coastguard Worker SkScalar fSweep;
124*c8dee2aaSAndroid Build Coastguard Worker };
125*c8dee2aaSAndroid Build Coastguard Worker const Arc noDrawArcs[] = {
126*c8dee2aaSAndroid Build Coastguard Worker // no sweep
127*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), 0, 0},
128*c8dee2aaSAndroid Build Coastguard Worker // empty rect in x
129*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(-kS, kS), 0, 90},
130*c8dee2aaSAndroid Build Coastguard Worker // empty rect in y
131*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, -kS), 0, 90},
132*c8dee2aaSAndroid Build Coastguard Worker // empty rect in x and y
133*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH( 0, 0), 0, 90},
134*c8dee2aaSAndroid Build Coastguard Worker };
135*c8dee2aaSAndroid Build Coastguard Worker const Arc arcs[] = {
136*c8dee2aaSAndroid Build Coastguard Worker // large start
137*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), 810.f, 90.f},
138*c8dee2aaSAndroid Build Coastguard Worker // large negative start
139*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), -810.f, 90.f},
140*c8dee2aaSAndroid Build Coastguard Worker // exactly 360 sweep
141*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), 0.f, 360.f},
142*c8dee2aaSAndroid Build Coastguard Worker // exactly -360 sweep
143*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), 0.f, -360.f},
144*c8dee2aaSAndroid Build Coastguard Worker // exactly 540 sweep
145*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), 0.f, 540.f},
146*c8dee2aaSAndroid Build Coastguard Worker // exactly -540 sweep
147*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), 0.f, -540.f},
148*c8dee2aaSAndroid Build Coastguard Worker // generic large sweep and large start
149*c8dee2aaSAndroid Build Coastguard Worker {SkRect::MakeWH(kS, kS), 1125.f, 990.f},
150*c8dee2aaSAndroid Build Coastguard Worker };
151*c8dee2aaSAndroid Build Coastguard Worker TArray<SkPaint> paints;
152*c8dee2aaSAndroid Build Coastguard Worker // fill
153*c8dee2aaSAndroid Build Coastguard Worker paints.push_back();
154*c8dee2aaSAndroid Build Coastguard Worker // stroke
155*c8dee2aaSAndroid Build Coastguard Worker paints.push_back().setStroke(true);
156*c8dee2aaSAndroid Build Coastguard Worker paints.back().setStrokeWidth(kS / 6.f);
157*c8dee2aaSAndroid Build Coastguard Worker // hairline
158*c8dee2aaSAndroid Build Coastguard Worker paints.push_back().setStroke(true);
159*c8dee2aaSAndroid Build Coastguard Worker paints.back().setStrokeWidth(0.f);
160*c8dee2aaSAndroid Build Coastguard Worker // stroke and fill
161*c8dee2aaSAndroid Build Coastguard Worker paints.push_back().setStyle(SkPaint::kStrokeAndFill_Style);
162*c8dee2aaSAndroid Build Coastguard Worker paints.back().setStrokeWidth(kS / 6.f);
163*c8dee2aaSAndroid Build Coastguard Worker // dash effect
164*c8dee2aaSAndroid Build Coastguard Worker paints.push_back().setStroke(true);
165*c8dee2aaSAndroid Build Coastguard Worker paints.back().setStrokeWidth(kS / 6.f);
166*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kDashIntervals[] = {kS / 15, 2 * kS / 15};
167*c8dee2aaSAndroid Build Coastguard Worker paints.back().setPathEffect(SkDashPathEffect::Make(kDashIntervals, 2, 0.f));
168*c8dee2aaSAndroid Build Coastguard Worker
169*c8dee2aaSAndroid Build Coastguard Worker constexpr SkScalar kPad = 20.f;
170*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kPad, kPad);
171*c8dee2aaSAndroid Build Coastguard Worker // This loop should draw nothing.
172*c8dee2aaSAndroid Build Coastguard Worker for (auto arc : noDrawArcs) {
173*c8dee2aaSAndroid Build Coastguard Worker for (auto paint : paints) {
174*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
175*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
176*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
177*c8dee2aaSAndroid Build Coastguard Worker }
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker
180*c8dee2aaSAndroid Build Coastguard Worker SkPaint linePaint;
181*c8dee2aaSAndroid Build Coastguard Worker linePaint.setAntiAlias(true);
182*c8dee2aaSAndroid Build Coastguard Worker linePaint.setColor(SK_ColorRED);
183*c8dee2aaSAndroid Build Coastguard Worker SkScalar midX = std::size(arcs) * (kS + kPad) - kPad/2.f;
184*c8dee2aaSAndroid Build Coastguard Worker SkScalar height = paints.size() * (kS + kPad);
185*c8dee2aaSAndroid Build Coastguard Worker canvas->drawLine(midX, -kPad, midX, height, linePaint);
186*c8dee2aaSAndroid Build Coastguard Worker
187*c8dee2aaSAndroid Build Coastguard Worker for (auto paint : paints) {
188*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
189*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
190*c8dee2aaSAndroid Build Coastguard Worker for (auto arc : arcs) {
191*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, false, paint);
192*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kS + kPad, 0.f);
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker for (auto arc : arcs) {
195*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(arc.fOval, arc.fStart, arc.fSweep, true, paint);
196*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kS + kPad, 0.f);
197*c8dee2aaSAndroid Build Coastguard Worker }
198*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
199*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(0, kS + kPad);
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker
203*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(onebadarc, canvas, 100, 100) {
204*c8dee2aaSAndroid Build Coastguard Worker SkPathBuilder path;
205*c8dee2aaSAndroid Build Coastguard Worker path.moveTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000)); // 20, 20
206*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0x4208918c), SkBits2Float(0x4208918c)); // 34.1421f, 34.1421f
207*c8dee2aaSAndroid Build Coastguard Worker path.conicTo(SkBits2Float(0x41a00000), SkBits2Float(0x42412318), // 20, 48.2843f
208*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c), // 5.85786f, 34.1421f
209*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x3f3504f3)); // 0.707107f
210*c8dee2aaSAndroid Build Coastguard Worker path.quadTo(SkBits2Float(0x40bb73a0), SkBits2Float(0x4208918c), // 5.85786f, 34.1421f
211*c8dee2aaSAndroid Build Coastguard Worker SkBits2Float(0x40bb73a2), SkBits2Float(0x4208918c)); // 5.85787f, 34.1421f
212*c8dee2aaSAndroid Build Coastguard Worker path.lineTo(SkBits2Float(0x41a00000), SkBits2Float(0x41a00000)); // 20, 20
213*c8dee2aaSAndroid Build Coastguard Worker path.close();
214*c8dee2aaSAndroid Build Coastguard Worker SkPaint p0;
215*c8dee2aaSAndroid Build Coastguard Worker p0.setColor(SK_ColorRED);
216*c8dee2aaSAndroid Build Coastguard Worker p0.setStrokeWidth(15.f);
217*c8dee2aaSAndroid Build Coastguard Worker p0.setStroke(true);
218*c8dee2aaSAndroid Build Coastguard Worker p0.setAlpha(100);
219*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(20, 0);
220*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(path.detach(), p0);
221*c8dee2aaSAndroid Build Coastguard Worker
222*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(SkRect{60, 0, 100, 40}, 45, 90, true, p0);
223*c8dee2aaSAndroid Build Coastguard Worker }
224*c8dee2aaSAndroid Build Coastguard Worker
225*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(crbug_888453, canvas, 480, 150) {
226*c8dee2aaSAndroid Build Coastguard Worker // Two GPU path renderers were using a too-large tolerance when chopping connics to quads.
227*c8dee2aaSAndroid Build Coastguard Worker // This manifested as not-very-round circular arcs at certain radii. All the arcs being drawn
228*c8dee2aaSAndroid Build Coastguard Worker // here should look like circles.
229*c8dee2aaSAndroid Build Coastguard Worker SkPaint fill;
230*c8dee2aaSAndroid Build Coastguard Worker fill.setAntiAlias(true);
231*c8dee2aaSAndroid Build Coastguard Worker SkPaint hairline = fill;
232*c8dee2aaSAndroid Build Coastguard Worker hairline.setStroke(true);
233*c8dee2aaSAndroid Build Coastguard Worker SkPaint stroke = hairline;
234*c8dee2aaSAndroid Build Coastguard Worker stroke.setStrokeWidth(2.0f);
235*c8dee2aaSAndroid Build Coastguard Worker int x = 4;
236*c8dee2aaSAndroid Build Coastguard Worker int y0 = 25, y1 = 75, y2 = 125;
237*c8dee2aaSAndroid Build Coastguard Worker for (int r = 2; r <= 20; ++r) {
238*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(SkRect::MakeXYWH(x - r, y0 - r, 2 * r, 2 * r), 0, 360, false, fill);
239*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(SkRect::MakeXYWH(x - r, y1 - r, 2 * r, 2 * r), 0, 360, false, hairline);
240*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(SkRect::MakeXYWH(x - r, y2 - r, 2 * r, 2 * r), 0, 360, false, stroke);
241*c8dee2aaSAndroid Build Coastguard Worker x += 2 * r + 4;
242*c8dee2aaSAndroid Build Coastguard Worker }
243*c8dee2aaSAndroid Build Coastguard Worker }
244*c8dee2aaSAndroid Build Coastguard Worker
245*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(circular_arc_stroke_matrix, canvas, 820, 1090) {
246*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kRadius = 40.f;
247*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kStrokeWidth = 5.f;
248*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kStart = 89.f;
249*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kSweep = 180.f/SK_ScalarPI; // one radian
250*c8dee2aaSAndroid Build Coastguard Worker
251*c8dee2aaSAndroid Build Coastguard Worker TArray<SkMatrix> matrices;
252*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setRotate(kRadius, kRadius, 45.f);
253*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back(SkMatrix::I());
254*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setAll(-1, 0, 2*kRadius,
255*c8dee2aaSAndroid Build Coastguard Worker 0, 1, 0,
256*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1);
257*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setAll( 1, 0, 0,
258*c8dee2aaSAndroid Build Coastguard Worker 0, -1, 2*kRadius,
259*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1);
260*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setAll( 1, 0, 0,
261*c8dee2aaSAndroid Build Coastguard Worker 0, -1, 2*kRadius,
262*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1);
263*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setAll( 0, -1, 2*kRadius,
264*c8dee2aaSAndroid Build Coastguard Worker -1, 0, 2*kRadius,
265*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1);
266*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setAll( 0, -1, 2*kRadius,
267*c8dee2aaSAndroid Build Coastguard Worker 1, 0, 0,
268*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1);
269*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setAll( 0, 1, 0,
270*c8dee2aaSAndroid Build Coastguard Worker 1, 0, 0,
271*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1);
272*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setAll( 0, 1, 0,
273*c8dee2aaSAndroid Build Coastguard Worker -1, 0, 2*kRadius,
274*c8dee2aaSAndroid Build Coastguard Worker 0, 0, 1);
275*c8dee2aaSAndroid Build Coastguard Worker int baseMatrixCnt = matrices.size();
276*c8dee2aaSAndroid Build Coastguard Worker
277*c8dee2aaSAndroid Build Coastguard Worker
278*c8dee2aaSAndroid Build Coastguard Worker SkMatrix tinyCW;
279*c8dee2aaSAndroid Build Coastguard Worker tinyCW.setRotate(0.001f, kRadius, kRadius);
280*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < baseMatrixCnt; ++i) {
281*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setConcat(matrices[i], tinyCW);
282*c8dee2aaSAndroid Build Coastguard Worker }
283*c8dee2aaSAndroid Build Coastguard Worker SkMatrix tinyCCW;
284*c8dee2aaSAndroid Build Coastguard Worker tinyCCW.setRotate(-0.001f, kRadius, kRadius);
285*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < baseMatrixCnt; ++i) {
286*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setConcat(matrices[i], tinyCCW);
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker SkMatrix cw45;
289*c8dee2aaSAndroid Build Coastguard Worker cw45.setRotate(45.f, kRadius, kRadius);
290*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < baseMatrixCnt; ++i) {
291*c8dee2aaSAndroid Build Coastguard Worker matrices.push_back().setConcat(matrices[i], cw45);
292*c8dee2aaSAndroid Build Coastguard Worker }
293*c8dee2aaSAndroid Build Coastguard Worker
294*c8dee2aaSAndroid Build Coastguard Worker int x = 0;
295*c8dee2aaSAndroid Build Coastguard Worker int y = 0;
296*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kPad = 2*kStrokeWidth;
297*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(kPad, kPad);
298*c8dee2aaSAndroid Build Coastguard Worker auto bounds = SkRect::MakeWH(2*kRadius, 2*kRadius);
299*c8dee2aaSAndroid Build Coastguard Worker for (auto cap : {SkPaint::kRound_Cap, SkPaint::kButt_Cap, SkPaint::kSquare_Cap}) {
300*c8dee2aaSAndroid Build Coastguard Worker for (const auto& m : matrices) {
301*c8dee2aaSAndroid Build Coastguard Worker SkPaint paint;
302*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeCap(cap);
303*c8dee2aaSAndroid Build Coastguard Worker paint.setAntiAlias(true);
304*c8dee2aaSAndroid Build Coastguard Worker paint.setStroke(true);
305*c8dee2aaSAndroid Build Coastguard Worker paint.setStrokeWidth(kStrokeWidth);
306*c8dee2aaSAndroid Build Coastguard Worker canvas->save();
307*c8dee2aaSAndroid Build Coastguard Worker canvas->translate(x * (2*kRadius + kPad), y * (2*kRadius + kPad));
308*c8dee2aaSAndroid Build Coastguard Worker canvas->concat(m);
309*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorRED);
310*c8dee2aaSAndroid Build Coastguard Worker paint.setAlpha(0x80);
311*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(bounds, kStart, kSweep, false, paint);
312*c8dee2aaSAndroid Build Coastguard Worker paint.setColor(SK_ColorBLUE);
313*c8dee2aaSAndroid Build Coastguard Worker paint.setAlpha(0x80);
314*c8dee2aaSAndroid Build Coastguard Worker canvas->drawArc(bounds, kStart, kSweep - 360.f, false, paint);
315*c8dee2aaSAndroid Build Coastguard Worker canvas->restore();
316*c8dee2aaSAndroid Build Coastguard Worker ++x;
317*c8dee2aaSAndroid Build Coastguard Worker if (x == baseMatrixCnt) {
318*c8dee2aaSAndroid Build Coastguard Worker x = 0;
319*c8dee2aaSAndroid Build Coastguard Worker ++y;
320*c8dee2aaSAndroid Build Coastguard Worker }
321*c8dee2aaSAndroid Build Coastguard Worker }
322*c8dee2aaSAndroid Build Coastguard Worker }
323*c8dee2aaSAndroid Build Coastguard Worker }
324*c8dee2aaSAndroid Build Coastguard Worker
325*c8dee2aaSAndroid Build Coastguard Worker DEF_SIMPLE_GM(crbug_1472747, canvas, 400, 400) {
__anon692beef00702(float cx, float cy, float radius, SkPath* path) 326*c8dee2aaSAndroid Build Coastguard Worker auto addCanvas2dCircleArcTo = [](float cx, float cy, float radius, SkPath* path) {
327*c8dee2aaSAndroid Build Coastguard Worker SkRect oval = SkRect::MakeLTRB(cx - radius, cy - radius, cx + radius, cy + radius);
328*c8dee2aaSAndroid Build Coastguard Worker // arcTo(oval, 0, 2pi, anticlockwise) gets split to 0->-180,-180->-360
329*c8dee2aaSAndroid Build Coastguard Worker path->arcTo(oval, 0.f, -180.f, false);
330*c8dee2aaSAndroid Build Coastguard Worker path->arcTo(oval, -180.f, -180.f, false);
331*c8dee2aaSAndroid Build Coastguard Worker };
332*c8dee2aaSAndroid Build Coastguard Worker
333*c8dee2aaSAndroid Build Coastguard Worker // This manually stroked circle is large enough to trigger pre-chopping in the
334*c8dee2aaSAndroid Build Coastguard Worker // tessellation path renderers, but uses a non-default winding mode, which
335*c8dee2aaSAndroid Build Coastguard Worker // originally was not preserved in the chopped path.
336*c8dee2aaSAndroid Build Coastguard Worker static constexpr float kRadius = 31000.f;
337*c8dee2aaSAndroid Build Coastguard Worker SkPath strokedCircle;
338*c8dee2aaSAndroid Build Coastguard Worker addCanvas2dCircleArcTo(0.f, kRadius + 10.f, kRadius, &strokedCircle); // inner
339*c8dee2aaSAndroid Build Coastguard Worker addCanvas2dCircleArcTo(0.f, kRadius + 10.f, kRadius + 5.f, &strokedCircle); // outer
340*c8dee2aaSAndroid Build Coastguard Worker strokedCircle.setFillType(SkPathFillType::kEvenOdd);
341*c8dee2aaSAndroid Build Coastguard Worker
342*c8dee2aaSAndroid Build Coastguard Worker SkPaint fill;
343*c8dee2aaSAndroid Build Coastguard Worker fill.setAntiAlias(true);
344*c8dee2aaSAndroid Build Coastguard Worker canvas->drawPath(strokedCircle, fill);
345*c8dee2aaSAndroid Build Coastguard Worker }
346