• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 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 "SkAnimTimer.h"
11 #include "SkCanvas.h"
12 #include "SkPathMeasure.h"
13 #include "SkRandom.h"
14 
15 class AddArcGM : public skiagm::GM {
16 public:
AddArcGM()17     AddArcGM() : fRotate(0) {}
18 
19 protected:
onShortName()20     SkString onShortName() override { return SkString("addarc"); }
21 
onISize()22     SkISize onISize() override { return SkISize::Make(1040, 1040); }
23 
onDraw(SkCanvas * canvas)24     void onDraw(SkCanvas* canvas) override {
25         canvas->translate(20, 20);
26 
27         SkRect r = SkRect::MakeWH(1000, 1000);
28 
29         SkPaint paint;
30         paint.setAntiAlias(true);
31         paint.setStyle(SkPaint::kStroke_Style);
32         paint.setStrokeWidth(15);
33 
34         const SkScalar inset = paint.getStrokeWidth() + 4;
35         const SkScalar sweepAngle = 345;
36         SkRandom rand;
37 
38         SkScalar sign = 1;
39         while (r.width() > paint.getStrokeWidth() * 3) {
40             paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
41             SkScalar startAngle = rand.nextUScalar1() * 360;
42 
43             SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
44             startAngle += fRotate * 360 * speed * sign;
45 
46             SkPath path;
47             path.addArc(r, startAngle, sweepAngle);
48             canvas->drawPath(path, paint);
49 
50             r.inset(inset, inset);
51             sign = -sign;
52         }
53     }
54 
onAnimate(const SkAnimTimer & timer)55     bool onAnimate(const SkAnimTimer& timer) override {
56         fRotate = timer.scaled(1, 360);
57         return true;
58     }
59 
60 private:
61     SkScalar fRotate;
62     typedef skiagm::GM INHERITED;
63 };
64 DEF_GM( return new AddArcGM; )
65 
66 ///////////////////////////////////////////////////
67 
68 #define R   400
69 
70 DEF_SIMPLE_GM(addarc_meas, canvas, 2*R + 40, 2*R + 40) {
71         canvas->translate(R + 20, R + 20);
72 
73         SkPaint paint;
74         paint.setAntiAlias(true);
75         paint.setStyle(SkPaint::kStroke_Style);
76 
77         SkPaint measPaint;
78         measPaint.setAntiAlias(true);
79         measPaint.setColor(SK_ColorRED);
80 
81         const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
82         canvas->drawOval(oval, paint);
83 
84         for (SkScalar deg = 0; deg < 360; deg += 10) {
85             const SkScalar rad = SkDegreesToRadians(deg);
86             SkScalar rx = SkScalarCos(rad) * R;
87             SkScalar ry = SkScalarSin(rad) * R;
88 
89             canvas->drawLine(0, 0, rx, ry, paint);
90 
91             SkPath path;
92             path.addArc(oval, 0, deg);
93             SkPathMeasure meas(path, false);
94             SkScalar arcLen = rad * R;
95             SkPoint pos;
96             if (meas.getPosTan(arcLen, &pos, nullptr)) {
97                 canvas->drawLine({0, 0}, pos, measPaint);
98             }
99         }
100 }
101 
102 ///////////////////////////////////////////////////
103 
104 // Emphasize drawing a stroked oval (containing conics) and then scaling the results up,
105 // to ensure that we compute the stroke taking the CTM into account
106 //
107 class StrokeCircleGM : public skiagm::GM {
108 public:
StrokeCircleGM()109     StrokeCircleGM() : fRotate(0) {}
110 
111 protected:
onShortName()112     SkString onShortName() override { return SkString("strokecircle"); }
113 
onISize()114     SkISize onISize() override { return SkISize::Make(520, 520); }
115 
onDraw(SkCanvas * canvas)116     void onDraw(SkCanvas* canvas) override {
117         canvas->scale(20, 20);
118         canvas->translate(13, 13);
119 
120         SkPaint paint;
121         paint.setAntiAlias(true);
122         paint.setStyle(SkPaint::kStroke_Style);
123         paint.setStrokeWidth(SK_Scalar1 / 2);
124 
125         const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
126         SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
127         SkRandom rand;
128 
129         SkScalar sign = 1;
130         while (r.width() > paint.getStrokeWidth() * 2) {
131             SkAutoCanvasRestore acr(canvas, true);
132             canvas->rotate(fRotate * sign);
133 
134             paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
135             canvas->drawOval(r, paint);
136             r.inset(delta, delta);
137             sign = -sign;
138         }
139     }
140 
onAnimate(const SkAnimTimer & timer)141     bool onAnimate(const SkAnimTimer& timer) override {
142         fRotate = timer.scaled(60, 360);
143         return true;
144     }
145 
146 private:
147     SkScalar fRotate;
148 
149     typedef skiagm::GM INHERITED;
150 };
151 DEF_GM( return new StrokeCircleGM; )
152 
153 //////////////////////
154 
155 // Fill circles and rotate them to test our Analytic Anti-Aliasing.
156 // This test is based on StrokeCircleGM.
157 class FillCircleGM : public skiagm::GM {
158 public:
FillCircleGM()159     FillCircleGM() : fRotate(0) {}
160 
161 protected:
onShortName()162     SkString onShortName() override { return SkString("fillcircle"); }
163 
onISize()164     SkISize onISize() override { return SkISize::Make(520, 520); }
165 
onDraw(SkCanvas * canvas)166     void onDraw(SkCanvas* canvas) override {
167         canvas->scale(20, 20);
168         canvas->translate(13, 13);
169 
170         SkPaint paint;
171         paint.setAntiAlias(true);
172         paint.setStyle(SkPaint::kStroke_Style);
173         paint.setStrokeWidth(SK_Scalar1 / 2);
174 
175         const SkScalar strokeWidth = paint.getStrokeWidth();
176         const SkScalar delta = strokeWidth * 3 / 2;
177         SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
178         SkRandom rand;
179 
180         // Reset style to fill. We only need stroke stype for producing delta and strokeWidth
181         paint.setStyle(SkPaint::kFill_Style);
182 
183         SkScalar sign = 1;
184         while (r.width() > strokeWidth * 2) {
185             SkAutoCanvasRestore acr(canvas, true);
186             canvas->rotate(fRotate * sign);
187             paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
188             canvas->drawOval(r, paint);
189             r.inset(delta, delta);
190             sign = -sign;
191         }
192     }
193 
onAnimate(const SkAnimTimer & timer)194     bool onAnimate(const SkAnimTimer& timer) override {
195         fRotate = timer.scaled(60, 360);
196         return true;
197     }
198 
199 private:
200     SkScalar fRotate;
201 
202     typedef skiagm::GM INHERITED;
203 };
DEF_GM(return new FillCircleGM;)204 DEF_GM( return new FillCircleGM; )
205 
206 //////////////////////
207 
208 static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
209                             SkScalar end, bool ccw, bool callArcTo) {
210     SkRect bounds = { x - r, y - r, x + r, y + r };
211     SkScalar sweep = ccw ? end - start : start - end;
212     if (callArcTo)
213         path->arcTo(bounds, start, sweep, false);
214     else
215         path->addArc(bounds, start, sweep);
216 }
217 
218 // Lifted from canvas-arc-circumference-fill-diffs.html
219 DEF_SIMPLE_GM(manyarcs, canvas, 620, 330) {
220         SkPaint paint;
221         paint.setAntiAlias(true);
222         paint.setStyle(SkPaint::kStroke_Style);
223 
224         canvas->translate(10, 10);
225 
226         // 20 angles.
227         SkScalar sweepAngles[] = {
228                            -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
229                            1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
230         };
231         for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
232             sweepAngles[i] *= 180;
233         }
234 
235         SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
236         for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
237             startAngles[i] *= 180;
238         }
239 
240         bool anticlockwise = false;
241         SkScalar sign = 1;
242         for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
243             if (i == SK_ARRAY_COUNT(startAngles)) {
244                 anticlockwise = true;
245                 sign = -1;
246             }
247             SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
248             canvas->save();
249             for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
250                 SkPath path;
251                 path.moveTo(0, 2);
252                 html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
253                                 anticlockwise, true);
254                 path.lineTo(0, 28);
255                 canvas->drawPath(path, paint);
256                 canvas->translate(30, 0);
257             }
258             canvas->restore();
259             canvas->translate(0, 40);
260         }
261 }
262 
263 // Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
264 DEF_SIMPLE_GM(tinyanglearcs, canvas, 620, 330) {
265         SkPaint paint;
266         paint.setAntiAlias(true);
267         paint.setStyle(SkPaint::kStroke_Style);
268 
269         canvas->translate(50, 50);
270 
271         SkScalar outerRadius = 100000.0f;
272         SkScalar innerRadius = outerRadius - 20.0f;
273         SkScalar centerX = 50;
274         SkScalar centerY = outerRadius;
275         SkScalar startAngles[] = { 1.5f * SK_ScalarPI , 1.501f * SK_ScalarPI  };
276         SkScalar sweepAngle = 10.0f / outerRadius;
277 
278         for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
279             SkPath path;
280             SkScalar endAngle = startAngles[i] + sweepAngle;
281             path.moveTo(centerX + innerRadius * sk_float_cos(startAngles[i]),
282                         centerY + innerRadius * sk_float_sin(startAngles[i]));
283             path.lineTo(centerX + outerRadius * sk_float_cos(startAngles[i]),
284                         centerY + outerRadius * sk_float_sin(startAngles[i]));
285             // A combination of tiny sweepAngle + large radius, we should draw a line.
286             html_canvas_arc(&path, centerX, outerRadius, outerRadius,
287                             startAngles[i] * 180 / SK_ScalarPI, endAngle * 180 / SK_ScalarPI,
288                             true, true);
289             path.lineTo(centerX + innerRadius * sk_float_cos(endAngle),
290                         centerY + innerRadius * sk_float_sin(endAngle));
291             html_canvas_arc(&path, centerX, outerRadius, innerRadius,
292                             endAngle * 180 / SK_ScalarPI, startAngles[i] * 180 / SK_ScalarPI,
293                             true, false);
294             canvas->drawPath(path, paint);
295             canvas->translate(20, 0);
296         }
297 }
298