blob: cfb8fed056b75512c041eb7cf5b034ccb8524c73 [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
Hal Canary607c44f2019-01-23 10:40:02 -050070DEF_SIMPLE_GM(addarc_meas, canvas, 2*R + 40, 2*R + 40) {
reed61adb1b2015-02-09 13:01:05 -080071 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;
halcanary96fcdcc2015-08-27 07:41:13 -070096 if (meas.getPosTan(arcLen, &pos, nullptr)) {
Hal Canary23e474c2017-05-15 13:35:35 -040097 canvas->drawLine({0, 0}, pos, measPaint);
reed61adb1b2015-02-09 13:01:05 -080098 }
99 }
Hal Canary607c44f2019-01-23 10:40:02 -0500100}
reed8ed666d2015-02-10 17:44:26 -0800101
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//
107class StrokeCircleGM : public skiagm::GM {
108public:
109 StrokeCircleGM() : fRotate(0) {}
halcanary9d524f22016-03-29 09:03:52 -0700110
reed8ed666d2015-02-10 17:44:26 -0800111protected:
mtklein36352bf2015-03-25 18:17:31 -0700112 SkString onShortName() override { return SkString("strokecircle"); }
halcanary9d524f22016-03-29 09:03:52 -0700113
mtklein36352bf2015-03-25 18:17:31 -0700114 SkISize onISize() override { return SkISize::Make(520, 520); }
halcanary9d524f22016-03-29 09:03:52 -0700115
mtklein36352bf2015-03-25 18:17:31 -0700116 void onDraw(SkCanvas* canvas) override {
reed8ed666d2015-02-10 17:44:26 -0800117 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
caryclark12596012015-07-29 05:27:47 -0700134 paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
reed8ed666d2015-02-10 17:44:26 -0800135 canvas->drawOval(r, paint);
136 r.inset(delta, delta);
137 sign = -sign;
138 }
139 }
140
mtklein36352bf2015-03-25 18:17:31 -0700141 bool onAnimate(const SkAnimTimer& timer) override {
reed8ed666d2015-02-10 17:44:26 -0800142 fRotate = timer.scaled(60, 360);
143 return true;
144 }
145
146private:
147 SkScalar fRotate;
148
149 typedef skiagm::GM INHERITED;
150};
151DEF_GM( return new StrokeCircleGM; )
reed9e779d42015-02-17 11:43:14 -0800152
153//////////////////////
154
liyuqiane60d8552016-10-03 13:49:37 -0700155// Fill circles and rotate them to test our Analytic Anti-Aliasing.
156// This test is based on StrokeCircleGM.
157class FillCircleGM : public skiagm::GM {
158public:
159 FillCircleGM() : fRotate(0) {}
160
161protected:
162 SkString onShortName() override { return SkString("fillcircle"); }
163
164 SkISize onISize() override { return SkISize::Make(520, 520); }
165
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
194 bool onAnimate(const SkAnimTimer& timer) override {
195 fRotate = timer.scaled(60, 360);
196 return true;
197 }
198
199private:
200 SkScalar fRotate;
201
202 typedef skiagm::GM INHERITED;
203};
204DEF_GM( return new FillCircleGM; )
205
206//////////////////////
207
reed9e779d42015-02-17 11:43:14 -0800208static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
xidachen6069dda2016-10-06 05:42:23 -0700209 SkScalar end, bool ccw, bool callArcTo) {
reed9e779d42015-02-17 11:43:14 -0800210 SkRect bounds = { x - r, y - r, x + r, y + r };
211 SkScalar sweep = ccw ? end - start : start - end;
xidachen6069dda2016-10-06 05:42:23 -0700212 if (callArcTo)
213 path->arcTo(bounds, start, sweep, false);
214 else
215 path->addArc(bounds, start, sweep);
reed9e779d42015-02-17 11:43:14 -0800216}
217
218// Lifted from canvas-arc-circumference-fill-diffs.html
Hal Canary607c44f2019-01-23 10:40:02 -0500219DEF_SIMPLE_GM(manyarcs, canvas, 620, 330) {
reed9e779d42015-02-17 11:43:14 -0800220 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 }
halcanary9d524f22016-03-29 09:03:52 -0700234
reed9e779d42015-02-17 11:43:14 -0800235 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 }
halcanary9d524f22016-03-29 09:03:52 -0700239
reed9e779d42015-02-17 11:43:14 -0800240 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),
xidachen6069dda2016-10-06 05:42:23 -0700253 anticlockwise, true);
reed9e779d42015-02-17 11:43:14 -0800254 path.lineTo(0, 28);
255 canvas->drawPath(path, paint);
256 canvas->translate(30, 0);
257 }
258 canvas->restore();
259 canvas->translate(0, 40);
260 }
Hal Canary607c44f2019-01-23 10:40:02 -0500261}
xidachen6069dda2016-10-06 05:42:23 -0700262
263// Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
Hal Canary607c44f2019-01-23 10:40:02 -0500264DEF_SIMPLE_GM(tinyanglearcs, canvas, 620, 330) {
xidachen6069dda2016-10-06 05:42:23 -0700265 SkPaint paint;
266 paint.setAntiAlias(true);
267 paint.setStyle(SkPaint::kStroke_Style);
268
269 canvas->translate(50, 50);
270
xidachen95e34a32016-10-19 10:24:28 -0700271 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 }
Hal Canary607c44f2019-01-23 10:40:02 -0500297}