blob: 763135fac57edf055781775799b194ae787c726f [file] [log] [blame]
reed19d8f9f2015-01-29 10:48:16 -08001/*
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"
Mike Klein33d20552017-03-22 13:47:51 -04009#include "sk_tool_utils.h"
reed76113a92015-02-02 12:55:02 -080010#include "SkAnimTimer.h"
reed19d8f9f2015-01-29 10:48:16 -080011#include "SkCanvas.h"
reed61adb1b2015-02-09 13:01:05 -080012#include "SkPathMeasure.h"
reed19d8f9f2015-01-29 10:48:16 -080013#include "SkRandom.h"
14
15class AddArcGM : public skiagm::GM {
reedd9adfe62015-02-01 19:01:04 -080016public:
17 AddArcGM() : fRotate(0) {}
18
reed19d8f9f2015-01-29 10:48:16 -080019protected:
mtklein36352bf2015-03-25 18:17:31 -070020 SkString onShortName() override { return SkString("addarc"); }
reed19d8f9f2015-01-29 10:48:16 -080021
mtklein36352bf2015-03-25 18:17:31 -070022 SkISize onISize() override { return SkISize::Make(1040, 1040); }
reed19d8f9f2015-01-29 10:48:16 -080023
mtklein36352bf2015-03-25 18:17:31 -070024 void onDraw(SkCanvas* canvas) override {
reed19d8f9f2015-01-29 10:48:16 -080025 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
reedd9adfe62015-02-01 19:01:04 -080038 SkScalar sign = 1;
reed19d8f9f2015-01-29 10:48:16 -080039 while (r.width() > paint.getStrokeWidth() * 3) {
caryclark12596012015-07-29 05:27:47 -070040 paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
reed19d8f9f2015-01-29 10:48:16 -080041 SkScalar startAngle = rand.nextUScalar1() * 360;
42
reedd9adfe62015-02-01 19:01:04 -080043 SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
44 startAngle += fRotate * 360 * speed * sign;
45
reed19d8f9f2015-01-29 10:48:16 -080046 SkPath path;
47 path.addArc(r, startAngle, sweepAngle);
48 canvas->drawPath(path, paint);
49
50 r.inset(inset, inset);
reedd9adfe62015-02-01 19:01:04 -080051 sign = -sign;
reed19d8f9f2015-01-29 10:48:16 -080052 }
53 }
54
mtklein36352bf2015-03-25 18:17:31 -070055 bool onAnimate(const SkAnimTimer& timer) override {
reed76113a92015-02-02 12:55:02 -080056 fRotate = timer.scaled(1, 360);
reedd9adfe62015-02-01 19:01:04 -080057 return true;
58 }
59
reed19d8f9f2015-01-29 10:48:16 -080060private:
reedd9adfe62015-02-01 19:01:04 -080061 SkScalar fRotate;
reed19d8f9f2015-01-29 10:48:16 -080062 typedef skiagm::GM INHERITED;
63};
64DEF_GM( return new AddArcGM; )
reed61adb1b2015-02-09 13:01:05 -080065
66///////////////////////////////////////////////////
67
68#define R 400
69
70class AddArcMeasGM : public skiagm::GM {
71public:
72 AddArcMeasGM() {}
73
74protected:
mtklein36352bf2015-03-25 18:17:31 -070075 SkString onShortName() override { return SkString("addarc_meas"); }
reed61adb1b2015-02-09 13:01:05 -080076
mtklein36352bf2015-03-25 18:17:31 -070077 SkISize onISize() override { return SkISize::Make(2*R + 40, 2*R + 40); }
reed61adb1b2015-02-09 13:01:05 -080078
mtklein36352bf2015-03-25 18:17:31 -070079 void onDraw(SkCanvas* canvas) override {
reed61adb1b2015-02-09 13:01:05 -080080 canvas->translate(R + 20, R + 20);
81
82 SkPaint paint;
83 paint.setAntiAlias(true);
84 paint.setStyle(SkPaint::kStroke_Style);
85
86 SkPaint measPaint;
87 measPaint.setAntiAlias(true);
88 measPaint.setColor(SK_ColorRED);
89
90 const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
91 canvas->drawOval(oval, paint);
92
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;
97
98 canvas->drawLine(0, 0, rx, ry, paint);
99
100 SkPath path;
101 path.addArc(oval, 0, deg);
102 SkPathMeasure meas(path, false);
103 SkScalar arcLen = rad * R;
104 SkPoint pos;
halcanary96fcdcc2015-08-27 07:41:13 -0700105 if (meas.getPosTan(arcLen, &pos, nullptr)) {
Hal Canary23e474c2017-05-15 13:35:35 -0400106 canvas->drawLine({0, 0}, pos, measPaint);
reed61adb1b2015-02-09 13:01:05 -0800107 }
108 }
109 }
110
111private:
112 typedef skiagm::GM INHERITED;
113};
114DEF_GM( return new AddArcMeasGM; )
reed8ed666d2015-02-10 17:44:26 -0800115
116///////////////////////////////////////////////////
117
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
120//
121class StrokeCircleGM : public skiagm::GM {
122public:
123 StrokeCircleGM() : fRotate(0) {}
halcanary9d524f22016-03-29 09:03:52 -0700124
reed8ed666d2015-02-10 17:44:26 -0800125protected:
mtklein36352bf2015-03-25 18:17:31 -0700126 SkString onShortName() override { return SkString("strokecircle"); }
halcanary9d524f22016-03-29 09:03:52 -0700127
mtklein36352bf2015-03-25 18:17:31 -0700128 SkISize onISize() override { return SkISize::Make(520, 520); }
halcanary9d524f22016-03-29 09:03:52 -0700129
mtklein36352bf2015-03-25 18:17:31 -0700130 void onDraw(SkCanvas* canvas) override {
reed8ed666d2015-02-10 17:44:26 -0800131 canvas->scale(20, 20);
132 canvas->translate(13, 13);
133
134 SkPaint paint;
135 paint.setAntiAlias(true);
136 paint.setStyle(SkPaint::kStroke_Style);
137 paint.setStrokeWidth(SK_Scalar1 / 2);
138
139 const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
140 SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
141 SkRandom rand;
142
143 SkScalar sign = 1;
144 while (r.width() > paint.getStrokeWidth() * 2) {
145 SkAutoCanvasRestore acr(canvas, true);
146 canvas->rotate(fRotate * sign);
147
caryclark12596012015-07-29 05:27:47 -0700148 paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
reed8ed666d2015-02-10 17:44:26 -0800149 canvas->drawOval(r, paint);
150 r.inset(delta, delta);
151 sign = -sign;
152 }
153 }
154
mtklein36352bf2015-03-25 18:17:31 -0700155 bool onAnimate(const SkAnimTimer& timer) override {
reed8ed666d2015-02-10 17:44:26 -0800156 fRotate = timer.scaled(60, 360);
157 return true;
158 }
159
160private:
161 SkScalar fRotate;
162
163 typedef skiagm::GM INHERITED;
164};
165DEF_GM( return new StrokeCircleGM; )
reed9e779d42015-02-17 11:43:14 -0800166
167//////////////////////
168
liyuqiane60d8552016-10-03 13:49:37 -0700169// Fill circles and rotate them to test our Analytic Anti-Aliasing.
170// This test is based on StrokeCircleGM.
171class FillCircleGM : public skiagm::GM {
172public:
173 FillCircleGM() : fRotate(0) {}
174
175protected:
176 SkString onShortName() override { return SkString("fillcircle"); }
177
178 SkISize onISize() override { return SkISize::Make(520, 520); }
179
180 void onDraw(SkCanvas* canvas) override {
181 canvas->scale(20, 20);
182 canvas->translate(13, 13);
183
184 SkPaint paint;
185 paint.setAntiAlias(true);
186 paint.setStyle(SkPaint::kStroke_Style);
187 paint.setStrokeWidth(SK_Scalar1 / 2);
188
189 const SkScalar strokeWidth = paint.getStrokeWidth();
190 const SkScalar delta = strokeWidth * 3 / 2;
191 SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
192 SkRandom rand;
193
194 // Reset style to fill. We only need stroke stype for producing delta and strokeWidth
195 paint.setStyle(SkPaint::kFill_Style);
196
197 SkScalar sign = 1;
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);
204 sign = -sign;
205 }
206 }
207
208 bool onAnimate(const SkAnimTimer& timer) override {
209 fRotate = timer.scaled(60, 360);
210 return true;
211 }
212
213private:
214 SkScalar fRotate;
215
216 typedef skiagm::GM INHERITED;
217};
218DEF_GM( return new FillCircleGM; )
219
220//////////////////////
221
reed9e779d42015-02-17 11:43:14 -0800222static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
xidachen6069dda2016-10-06 05:42:23 -0700223 SkScalar end, bool ccw, bool callArcTo) {
reed9e779d42015-02-17 11:43:14 -0800224 SkRect bounds = { x - r, y - r, x + r, y + r };
225 SkScalar sweep = ccw ? end - start : start - end;
xidachen6069dda2016-10-06 05:42:23 -0700226 if (callArcTo)
227 path->arcTo(bounds, start, sweep, false);
228 else
229 path->addArc(bounds, start, sweep);
reed9e779d42015-02-17 11:43:14 -0800230}
231
232// Lifted from canvas-arc-circumference-fill-diffs.html
233class ManyArcsGM : public skiagm::GM {
234public:
235 ManyArcsGM() {}
halcanary9d524f22016-03-29 09:03:52 -0700236
reed9e779d42015-02-17 11:43:14 -0800237protected:
mtklein36352bf2015-03-25 18:17:31 -0700238 SkString onShortName() override { return SkString("manyarcs"); }
halcanary9d524f22016-03-29 09:03:52 -0700239
mtklein36352bf2015-03-25 18:17:31 -0700240 SkISize onISize() override { return SkISize::Make(620, 330); }
halcanary9d524f22016-03-29 09:03:52 -0700241
mtklein36352bf2015-03-25 18:17:31 -0700242 void onDraw(SkCanvas* canvas) override {
reed9e779d42015-02-17 11:43:14 -0800243 SkPaint paint;
244 paint.setAntiAlias(true);
245 paint.setStyle(SkPaint::kStroke_Style);
246
247 canvas->translate(10, 10);
248
249 // 20 angles.
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
253 };
254 for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
255 sweepAngles[i] *= 180;
256 }
halcanary9d524f22016-03-29 09:03:52 -0700257
reed9e779d42015-02-17 11:43:14 -0800258 SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
259 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
260 startAngles[i] *= 180;
261 }
halcanary9d524f22016-03-29 09:03:52 -0700262
reed9e779d42015-02-17 11:43:14 -0800263 bool anticlockwise = false;
264 SkScalar sign = 1;
265 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
266 if (i == SK_ARRAY_COUNT(startAngles)) {
267 anticlockwise = true;
268 sign = -1;
269 }
270 SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
271 canvas->save();
272 for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
273 SkPath path;
274 path.moveTo(0, 2);
275 html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
xidachen6069dda2016-10-06 05:42:23 -0700276 anticlockwise, true);
reed9e779d42015-02-17 11:43:14 -0800277 path.lineTo(0, 28);
278 canvas->drawPath(path, paint);
279 canvas->translate(30, 0);
280 }
281 canvas->restore();
282 canvas->translate(0, 40);
283 }
284 }
halcanary9d524f22016-03-29 09:03:52 -0700285
reed9e779d42015-02-17 11:43:14 -0800286private:
287 typedef skiagm::GM INHERITED;
288};
289DEF_GM( return new ManyArcsGM; )
xidachen6069dda2016-10-06 05:42:23 -0700290
291// Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
292class TinyAngleBigRadiusArcsGM : public skiagm::GM {
293public:
294 TinyAngleBigRadiusArcsGM() {}
295
296protected:
297 SkString onShortName() override { return SkString("tinyanglearcs"); }
298
299 SkISize onISize() override { return SkISize::Make(620, 330); }
300
301 void onDraw(SkCanvas* canvas) override {
302 SkPaint paint;
303 paint.setAntiAlias(true);
304 paint.setStyle(SkPaint::kStroke_Style);
305
306 canvas->translate(50, 50);
307
xidachen95e34a32016-10-19 10:24:28 -0700308 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;
314
315 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
316 SkPath path;
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,
325 true, true);
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,
330 true, false);
331 canvas->drawPath(path, paint);
332 canvas->translate(20, 0);
333 }
xidachen6069dda2016-10-06 05:42:23 -0700334 }
335
336private:
337 typedef skiagm::GM INHERITED;
338};
339DEF_GM( return new TinyAngleBigRadiusArcsGM; )