2 * Copyright 2015 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "sk_tool_utils.h"
10 #include "SkAnimTimer.h"
12 #include "SkPathMeasure.h"
15 class AddArcGM : public skiagm::GM {
17 AddArcGM() : fRotate(0) {}
20 SkString onShortName() override { return SkString("addarc"); }
22 SkISize onISize() override { return SkISize::Make(1040, 1040); }
24 void onDraw(SkCanvas* canvas) override {
25 canvas->translate(20, 20);
27 SkRect r = SkRect::MakeWH(1000, 1000);
30 paint.setAntiAlias(true);
31 paint.setStyle(SkPaint::kStroke_Style);
32 paint.setStrokeWidth(15);
34 const SkScalar inset = paint.getStrokeWidth() + 4;
35 const SkScalar sweepAngle = 345;
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;
43 SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
44 startAngle += fRotate * 360 * speed * sign;
47 path.addArc(r, startAngle, sweepAngle);
48 canvas->drawPath(path, paint);
50 r.inset(inset, inset);
55 bool onAnimate(const SkAnimTimer& timer) override {
56 fRotate = timer.scaled(1, 360);
62 typedef skiagm::GM INHERITED;
64 DEF_GM( return new AddArcGM; )
66 ///////////////////////////////////////////////////
70 class AddArcMeasGM : public skiagm::GM {
75 SkString onShortName() override { return SkString("addarc_meas"); }
77 SkISize onISize() override { return SkISize::Make(2*R + 40, 2*R + 40); }
79 void onDraw(SkCanvas* canvas) override {
80 canvas->translate(R + 20, R + 20);
83 paint.setAntiAlias(true);
84 paint.setStyle(SkPaint::kStroke_Style);
87 measPaint.setAntiAlias(true);
88 measPaint.setColor(SK_ColorRED);
90 const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
91 canvas->drawOval(oval, paint);
93 for (SkScalar deg = 0; deg < 360; deg += 10) {
94 const SkScalar rad = SkDegreesToRadians(deg);
95 SkScalar rx = SkScalarCos(rad) * R;
96 SkScalar ry = SkScalarSin(rad) * R;
98 canvas->drawLine(0, 0, rx, ry, paint);
101 path.addArc(oval, 0, deg);
102 SkPathMeasure meas(path, false);
103 SkScalar arcLen = rad * R;
105 if (meas.getPosTan(arcLen, &pos, nullptr)) {
106 canvas->drawLine({0, 0}, pos, measPaint);
112 typedef skiagm::GM INHERITED;
114 DEF_GM( return new AddArcMeasGM; )
116 ///////////////////////////////////////////////////
118 // Emphasize drawing a stroked oval (containing conics) and then scaling the results up,
119 // to ensure that we compute the stroke taking the CTM into account
121 class StrokeCircleGM : public skiagm::GM {
123 StrokeCircleGM() : fRotate(0) {}
126 SkString onShortName() override { return SkString("strokecircle"); }
128 SkISize onISize() override { return SkISize::Make(520, 520); }
130 void onDraw(SkCanvas* canvas) override {
131 canvas->scale(20, 20);
132 canvas->translate(13, 13);
135 paint.setAntiAlias(true);
136 paint.setStyle(SkPaint::kStroke_Style);
137 paint.setStrokeWidth(SK_Scalar1 / 2);
139 const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
140 SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
144 while (r.width() > paint.getStrokeWidth() * 2) {
145 SkAutoCanvasRestore acr(canvas, true);
146 canvas->rotate(fRotate * sign);
148 paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
149 canvas->drawOval(r, paint);
150 r.inset(delta, delta);
155 bool onAnimate(const SkAnimTimer& timer) override {
156 fRotate = timer.scaled(60, 360);
163 typedef skiagm::GM INHERITED;
165 DEF_GM( return new StrokeCircleGM; )
167 //////////////////////
169 // Fill circles and rotate them to test our Analytic Anti-Aliasing.
170 // This test is based on StrokeCircleGM.
171 class FillCircleGM : public skiagm::GM {
173 FillCircleGM() : fRotate(0) {}
176 SkString onShortName() override { return SkString("fillcircle"); }
178 SkISize onISize() override { return SkISize::Make(520, 520); }
180 void onDraw(SkCanvas* canvas) override {
181 canvas->scale(20, 20);
182 canvas->translate(13, 13);
185 paint.setAntiAlias(true);
186 paint.setStyle(SkPaint::kStroke_Style);
187 paint.setStrokeWidth(SK_Scalar1 / 2);
189 const SkScalar strokeWidth = paint.getStrokeWidth();
190 const SkScalar delta = strokeWidth * 3 / 2;
191 SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
194 // Reset style to fill. We only need stroke stype for producing delta and strokeWidth
195 paint.setStyle(SkPaint::kFill_Style);
198 while (r.width() > strokeWidth * 2) {
199 SkAutoCanvasRestore acr(canvas, true);
200 canvas->rotate(fRotate * sign);
201 paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
202 canvas->drawOval(r, paint);
203 r.inset(delta, delta);
208 bool onAnimate(const SkAnimTimer& timer) override {
209 fRotate = timer.scaled(60, 360);
216 typedef skiagm::GM INHERITED;
218 DEF_GM( return new FillCircleGM; )
220 //////////////////////
222 static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
223 SkScalar end, bool ccw, bool callArcTo) {
224 SkRect bounds = { x - r, y - r, x + r, y + r };
225 SkScalar sweep = ccw ? end - start : start - end;
227 path->arcTo(bounds, start, sweep, false);
229 path->addArc(bounds, start, sweep);
232 // Lifted from canvas-arc-circumference-fill-diffs.html
233 class ManyArcsGM : public skiagm::GM {
238 SkString onShortName() override { return SkString("manyarcs"); }
240 SkISize onISize() override { return SkISize::Make(620, 330); }
242 void onDraw(SkCanvas* canvas) override {
244 paint.setAntiAlias(true);
245 paint.setStyle(SkPaint::kStroke_Style);
247 canvas->translate(10, 10);
250 SkScalar sweepAngles[] = {
251 -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
252 1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
254 for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
255 sweepAngles[i] *= 180;
258 SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
259 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
260 startAngles[i] *= 180;
263 bool anticlockwise = false;
265 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
266 if (i == SK_ARRAY_COUNT(startAngles)) {
267 anticlockwise = true;
270 SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
272 for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
275 html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
276 anticlockwise, true);
278 canvas->drawPath(path, paint);
279 canvas->translate(30, 0);
282 canvas->translate(0, 40);
287 typedef skiagm::GM INHERITED;
289 DEF_GM( return new ManyArcsGM; )
291 // Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
292 class TinyAngleBigRadiusArcsGM : public skiagm::GM {
294 TinyAngleBigRadiusArcsGM() {}
297 SkString onShortName() override { return SkString("tinyanglearcs"); }
299 SkISize onISize() override { return SkISize::Make(620, 330); }
301 void onDraw(SkCanvas* canvas) override {
303 paint.setAntiAlias(true);
304 paint.setStyle(SkPaint::kStroke_Style);
306 canvas->translate(50, 50);
308 SkScalar outerRadius = 100000.0f;
309 SkScalar innerRadius = outerRadius - 20.0f;
310 SkScalar centerX = 50;
311 SkScalar centerY = outerRadius;
312 SkScalar startAngles[] = { 1.5f * SK_ScalarPI , 1.501f * SK_ScalarPI };
313 SkScalar sweepAngle = 10.0f / outerRadius;
315 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
317 SkScalar endAngle = startAngles[i] + sweepAngle;
318 path.moveTo(centerX + innerRadius * sk_float_cos(startAngles[i]),
319 centerY + innerRadius * sk_float_sin(startAngles[i]));
320 path.lineTo(centerX + outerRadius * sk_float_cos(startAngles[i]),
321 centerY + outerRadius * sk_float_sin(startAngles[i]));
322 // A combination of tiny sweepAngle + large radius, we should draw a line.
323 html_canvas_arc(&path, centerX, outerRadius, outerRadius,
324 startAngles[i] * 180 / SK_ScalarPI, endAngle * 180 / SK_ScalarPI,
326 path.lineTo(centerX + innerRadius * sk_float_cos(endAngle),
327 centerY + innerRadius * sk_float_sin(endAngle));
328 html_canvas_arc(&path, centerX, outerRadius, innerRadius,
329 endAngle * 180 / SK_ScalarPI, startAngles[i] * 180 / SK_ScalarPI,
331 canvas->drawPath(path, paint);
332 canvas->translate(20, 0);
337 typedef skiagm::GM INHERITED;
339 DEF_GM( return new TinyAngleBigRadiusArcsGM; )