blob: 77d0db7bdc6df480bfedc1f61ae4416ac43b7b07 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
9#include "include/core/SkCanvas.h"
Ben Wagnerd1701ba2019-04-30 13:44:26 -040010#include "include/core/SkColor.h"
11#include "include/core/SkPaint.h"
12#include "include/core/SkPath.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/core/SkPathMeasure.h"
Ben Wagnerd1701ba2019-04-30 13:44:26 -040014#include "include/core/SkPoint.h"
15#include "include/core/SkRect.h"
16#include "include/core/SkScalar.h"
17#include "include/core/SkSize.h"
18#include "include/core/SkString.h"
19#include "include/core/SkTypes.h"
20#include "include/private/SkFloatingPoint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "include/utils/SkRandom.h"
22#include "tools/ToolUtils.h"
Hal Canary41248072019-07-11 16:32:53 -040023#include "tools/timer/TimeUtils.h"
reed19d8f9f2015-01-29 10:48:16 -080024
25class AddArcGM : public skiagm::GM {
reedd9adfe62015-02-01 19:01:04 -080026public:
27 AddArcGM() : fRotate(0) {}
28
reed19d8f9f2015-01-29 10:48:16 -080029protected:
mtklein36352bf2015-03-25 18:17:31 -070030 SkString onShortName() override { return SkString("addarc"); }
reed19d8f9f2015-01-29 10:48:16 -080031
mtklein36352bf2015-03-25 18:17:31 -070032 SkISize onISize() override { return SkISize::Make(1040, 1040); }
reed19d8f9f2015-01-29 10:48:16 -080033
mtklein36352bf2015-03-25 18:17:31 -070034 void onDraw(SkCanvas* canvas) override {
reed19d8f9f2015-01-29 10:48:16 -080035 canvas->translate(20, 20);
36
37 SkRect r = SkRect::MakeWH(1000, 1000);
38
39 SkPaint paint;
40 paint.setAntiAlias(true);
41 paint.setStyle(SkPaint::kStroke_Style);
42 paint.setStrokeWidth(15);
43
44 const SkScalar inset = paint.getStrokeWidth() + 4;
45 const SkScalar sweepAngle = 345;
46 SkRandom rand;
47
reedd9adfe62015-02-01 19:01:04 -080048 SkScalar sign = 1;
reed19d8f9f2015-01-29 10:48:16 -080049 while (r.width() > paint.getStrokeWidth() * 3) {
Mike Kleinea3f0142019-03-20 11:12:10 -050050 paint.setColor(ToolUtils::color_to_565(rand.nextU() | (0xFF << 24)));
reed19d8f9f2015-01-29 10:48:16 -080051 SkScalar startAngle = rand.nextUScalar1() * 360;
52
reedd9adfe62015-02-01 19:01:04 -080053 SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
54 startAngle += fRotate * 360 * speed * sign;
55
reed19d8f9f2015-01-29 10:48:16 -080056 SkPath path;
57 path.addArc(r, startAngle, sweepAngle);
58 canvas->drawPath(path, paint);
59
60 r.inset(inset, inset);
reedd9adfe62015-02-01 19:01:04 -080061 sign = -sign;
reed19d8f9f2015-01-29 10:48:16 -080062 }
63 }
64
Hal Canary41248072019-07-11 16:32:53 -040065 bool onAnimate(double nanos) override {
66 fRotate = TimeUtils::Scaled(1e-9 * nanos, 1, 360);
reedd9adfe62015-02-01 19:01:04 -080067 return true;
68 }
69
reed19d8f9f2015-01-29 10:48:16 -080070private:
reedd9adfe62015-02-01 19:01:04 -080071 SkScalar fRotate;
reed19d8f9f2015-01-29 10:48:16 -080072 typedef skiagm::GM INHERITED;
73};
74DEF_GM( return new AddArcGM; )
reed61adb1b2015-02-09 13:01:05 -080075
76///////////////////////////////////////////////////
77
78#define R 400
79
Hal Canary607c44f2019-01-23 10:40:02 -050080DEF_SIMPLE_GM(addarc_meas, canvas, 2*R + 40, 2*R + 40) {
reed61adb1b2015-02-09 13:01:05 -080081 canvas->translate(R + 20, R + 20);
82
83 SkPaint paint;
84 paint.setAntiAlias(true);
85 paint.setStyle(SkPaint::kStroke_Style);
86
87 SkPaint measPaint;
88 measPaint.setAntiAlias(true);
89 measPaint.setColor(SK_ColorRED);
90
91 const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
92 canvas->drawOval(oval, paint);
93
94 for (SkScalar deg = 0; deg < 360; deg += 10) {
95 const SkScalar rad = SkDegreesToRadians(deg);
96 SkScalar rx = SkScalarCos(rad) * R;
97 SkScalar ry = SkScalarSin(rad) * R;
98
99 canvas->drawLine(0, 0, rx, ry, paint);
100
101 SkPath path;
102 path.addArc(oval, 0, deg);
103 SkPathMeasure meas(path, false);
104 SkScalar arcLen = rad * R;
105 SkPoint pos;
halcanary96fcdcc2015-08-27 07:41:13 -0700106 if (meas.getPosTan(arcLen, &pos, nullptr)) {
Hal Canary23e474c2017-05-15 13:35:35 -0400107 canvas->drawLine({0, 0}, pos, measPaint);
reed61adb1b2015-02-09 13:01:05 -0800108 }
109 }
Hal Canary607c44f2019-01-23 10:40:02 -0500110}
reed8ed666d2015-02-10 17:44:26 -0800111
112///////////////////////////////////////////////////
113
114// Emphasize drawing a stroked oval (containing conics) and then scaling the results up,
115// to ensure that we compute the stroke taking the CTM into account
116//
117class StrokeCircleGM : public skiagm::GM {
118public:
119 StrokeCircleGM() : fRotate(0) {}
halcanary9d524f22016-03-29 09:03:52 -0700120
reed8ed666d2015-02-10 17:44:26 -0800121protected:
mtklein36352bf2015-03-25 18:17:31 -0700122 SkString onShortName() override { return SkString("strokecircle"); }
halcanary9d524f22016-03-29 09:03:52 -0700123
mtklein36352bf2015-03-25 18:17:31 -0700124 SkISize onISize() override { return SkISize::Make(520, 520); }
halcanary9d524f22016-03-29 09:03:52 -0700125
mtklein36352bf2015-03-25 18:17:31 -0700126 void onDraw(SkCanvas* canvas) override {
reed8ed666d2015-02-10 17:44:26 -0800127 canvas->scale(20, 20);
128 canvas->translate(13, 13);
129
130 SkPaint paint;
131 paint.setAntiAlias(true);
132 paint.setStyle(SkPaint::kStroke_Style);
133 paint.setStrokeWidth(SK_Scalar1 / 2);
134
135 const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
136 SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
137 SkRandom rand;
138
139 SkScalar sign = 1;
140 while (r.width() > paint.getStrokeWidth() * 2) {
141 SkAutoCanvasRestore acr(canvas, true);
142 canvas->rotate(fRotate * sign);
143
Mike Kleinea3f0142019-03-20 11:12:10 -0500144 paint.setColor(ToolUtils::color_to_565(rand.nextU() | (0xFF << 24)));
reed8ed666d2015-02-10 17:44:26 -0800145 canvas->drawOval(r, paint);
146 r.inset(delta, delta);
147 sign = -sign;
148 }
149 }
150
Hal Canary41248072019-07-11 16:32:53 -0400151 bool onAnimate(double nanos) override {
152 fRotate = TimeUtils::Scaled(1e-9 * nanos, 60, 360);
reed8ed666d2015-02-10 17:44:26 -0800153 return true;
154 }
155
156private:
157 SkScalar fRotate;
158
159 typedef skiagm::GM INHERITED;
160};
161DEF_GM( return new StrokeCircleGM; )
reed9e779d42015-02-17 11:43:14 -0800162
163//////////////////////
164
liyuqiane60d8552016-10-03 13:49:37 -0700165// Fill circles and rotate them to test our Analytic Anti-Aliasing.
166// This test is based on StrokeCircleGM.
167class FillCircleGM : public skiagm::GM {
168public:
169 FillCircleGM() : fRotate(0) {}
170
171protected:
172 SkString onShortName() override { return SkString("fillcircle"); }
173
174 SkISize onISize() override { return SkISize::Make(520, 520); }
175
176 void onDraw(SkCanvas* canvas) override {
177 canvas->scale(20, 20);
178 canvas->translate(13, 13);
179
180 SkPaint paint;
181 paint.setAntiAlias(true);
182 paint.setStyle(SkPaint::kStroke_Style);
183 paint.setStrokeWidth(SK_Scalar1 / 2);
184
185 const SkScalar strokeWidth = paint.getStrokeWidth();
186 const SkScalar delta = strokeWidth * 3 / 2;
187 SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
188 SkRandom rand;
189
190 // Reset style to fill. We only need stroke stype for producing delta and strokeWidth
191 paint.setStyle(SkPaint::kFill_Style);
192
193 SkScalar sign = 1;
194 while (r.width() > strokeWidth * 2) {
195 SkAutoCanvasRestore acr(canvas, true);
196 canvas->rotate(fRotate * sign);
Mike Kleinea3f0142019-03-20 11:12:10 -0500197 paint.setColor(ToolUtils::color_to_565(rand.nextU() | (0xFF << 24)));
liyuqiane60d8552016-10-03 13:49:37 -0700198 canvas->drawOval(r, paint);
199 r.inset(delta, delta);
200 sign = -sign;
201 }
202 }
203
Hal Canary41248072019-07-11 16:32:53 -0400204 bool onAnimate(double nanos) override {
205 fRotate = TimeUtils::Scaled(1e-9 * nanos, 60, 360);
liyuqiane60d8552016-10-03 13:49:37 -0700206 return true;
207 }
208
209private:
210 SkScalar fRotate;
211
212 typedef skiagm::GM INHERITED;
213};
214DEF_GM( return new FillCircleGM; )
215
216//////////////////////
217
reed9e779d42015-02-17 11:43:14 -0800218static void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
xidachen6069dda2016-10-06 05:42:23 -0700219 SkScalar end, bool ccw, bool callArcTo) {
reed9e779d42015-02-17 11:43:14 -0800220 SkRect bounds = { x - r, y - r, x + r, y + r };
221 SkScalar sweep = ccw ? end - start : start - end;
xidachen6069dda2016-10-06 05:42:23 -0700222 if (callArcTo)
223 path->arcTo(bounds, start, sweep, false);
224 else
225 path->addArc(bounds, start, sweep);
reed9e779d42015-02-17 11:43:14 -0800226}
227
228// Lifted from canvas-arc-circumference-fill-diffs.html
Hal Canary607c44f2019-01-23 10:40:02 -0500229DEF_SIMPLE_GM(manyarcs, canvas, 620, 330) {
reed9e779d42015-02-17 11:43:14 -0800230 SkPaint paint;
231 paint.setAntiAlias(true);
232 paint.setStyle(SkPaint::kStroke_Style);
233
234 canvas->translate(10, 10);
235
236 // 20 angles.
237 SkScalar sweepAngles[] = {
238 -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
239 1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
240 };
241 for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
242 sweepAngles[i] *= 180;
243 }
halcanary9d524f22016-03-29 09:03:52 -0700244
reed9e779d42015-02-17 11:43:14 -0800245 SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
246 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
247 startAngles[i] *= 180;
248 }
halcanary9d524f22016-03-29 09:03:52 -0700249
reed9e779d42015-02-17 11:43:14 -0800250 bool anticlockwise = false;
251 SkScalar sign = 1;
252 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
253 if (i == SK_ARRAY_COUNT(startAngles)) {
254 anticlockwise = true;
255 sign = -1;
256 }
257 SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
258 canvas->save();
259 for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
260 SkPath path;
261 path.moveTo(0, 2);
262 html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
xidachen6069dda2016-10-06 05:42:23 -0700263 anticlockwise, true);
reed9e779d42015-02-17 11:43:14 -0800264 path.lineTo(0, 28);
265 canvas->drawPath(path, paint);
266 canvas->translate(30, 0);
267 }
268 canvas->restore();
269 canvas->translate(0, 40);
270 }
Hal Canary607c44f2019-01-23 10:40:02 -0500271}
xidachen6069dda2016-10-06 05:42:23 -0700272
273// Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
Hal Canary607c44f2019-01-23 10:40:02 -0500274DEF_SIMPLE_GM(tinyanglearcs, canvas, 620, 330) {
xidachen6069dda2016-10-06 05:42:23 -0700275 SkPaint paint;
276 paint.setAntiAlias(true);
277 paint.setStyle(SkPaint::kStroke_Style);
278
279 canvas->translate(50, 50);
280
xidachen95e34a32016-10-19 10:24:28 -0700281 SkScalar outerRadius = 100000.0f;
282 SkScalar innerRadius = outerRadius - 20.0f;
283 SkScalar centerX = 50;
284 SkScalar centerY = outerRadius;
285 SkScalar startAngles[] = { 1.5f * SK_ScalarPI , 1.501f * SK_ScalarPI };
286 SkScalar sweepAngle = 10.0f / outerRadius;
287
288 for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
289 SkPath path;
290 SkScalar endAngle = startAngles[i] + sweepAngle;
291 path.moveTo(centerX + innerRadius * sk_float_cos(startAngles[i]),
292 centerY + innerRadius * sk_float_sin(startAngles[i]));
293 path.lineTo(centerX + outerRadius * sk_float_cos(startAngles[i]),
294 centerY + outerRadius * sk_float_sin(startAngles[i]));
295 // A combination of tiny sweepAngle + large radius, we should draw a line.
296 html_canvas_arc(&path, centerX, outerRadius, outerRadius,
297 startAngles[i] * 180 / SK_ScalarPI, endAngle * 180 / SK_ScalarPI,
298 true, true);
299 path.lineTo(centerX + innerRadius * sk_float_cos(endAngle),
300 centerY + innerRadius * sk_float_sin(endAngle));
301 html_canvas_arc(&path, centerX, outerRadius, innerRadius,
302 endAngle * 180 / SK_ScalarPI, startAngles[i] * 180 / SK_ScalarPI,
303 true, false);
304 canvas->drawPath(path, paint);
305 canvas->translate(20, 0);
306 }
Hal Canary607c44f2019-01-23 10:40:02 -0500307}