Add fixes & test for isConfigTexturable and isConfigRenderable
[platform/upstream/libSkiaSharp.git] / gm / addarc.cpp
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:
17     AddArcGM() : fRotate(0) {}
18
19 protected:
20     SkString onShortName() override { return SkString("addarc"); }
21
22     SkISize onISize() override { return SkISize::Make(1040, 1040); }
23
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
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 class AddArcMeasGM : public skiagm::GM {
71 public:
72     AddArcMeasGM() {}
73
74 protected:
75     SkString onShortName() override { return SkString("addarc_meas"); }
76
77     SkISize onISize() override { return SkISize::Make(2*R + 40, 2*R + 40); }
78
79     void onDraw(SkCanvas* canvas) override {
80         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;
105             if (meas.getPosTan(arcLen, &pos, nullptr)) {
106                 canvas->drawLine({0, 0}, pos, measPaint);
107             }
108         }
109     }
110
111 private:
112     typedef skiagm::GM INHERITED;
113 };
114 DEF_GM( return new AddArcMeasGM; )
115
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 //
121 class StrokeCircleGM : public skiagm::GM {
122 public:
123     StrokeCircleGM() : fRotate(0) {}
124
125 protected:
126     SkString onShortName() override { return SkString("strokecircle"); }
127
128     SkISize onISize() override { return SkISize::Make(520, 520); }
129
130     void onDraw(SkCanvas* canvas) override {
131         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
148             paint.setColor(sk_tool_utils::color_to_565(rand.nextU() | (0xFF << 24)));
149             canvas->drawOval(r, paint);
150             r.inset(delta, delta);
151             sign = -sign;
152         }
153     }
154
155     bool onAnimate(const SkAnimTimer& timer) override {
156         fRotate = timer.scaled(60, 360);
157         return true;
158     }
159
160 private:
161     SkScalar fRotate;
162
163     typedef skiagm::GM INHERITED;
164 };
165 DEF_GM( return new StrokeCircleGM; )
166
167 //////////////////////
168
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 {
172 public:
173     FillCircleGM() : fRotate(0) {}
174
175 protected:
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
213 private:
214     SkScalar fRotate;
215
216     typedef skiagm::GM INHERITED;
217 };
218 DEF_GM( return new FillCircleGM; )
219
220 //////////////////////
221
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;
226     if (callArcTo)
227         path->arcTo(bounds, start, sweep, false);
228     else
229         path->addArc(bounds, start, sweep);
230 }
231
232 // Lifted from canvas-arc-circumference-fill-diffs.html
233 class ManyArcsGM : public skiagm::GM {
234 public:
235     ManyArcsGM() {}
236
237 protected:
238     SkString onShortName() override { return SkString("manyarcs"); }
239
240     SkISize onISize() override { return SkISize::Make(620, 330); }
241
242     void onDraw(SkCanvas* canvas) override {
243         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         }
257
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;
261         }
262
263         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),
276                                 anticlockwise, true);
277                 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     }
285
286 private:
287     typedef skiagm::GM INHERITED;
288 };
289 DEF_GM( return new ManyArcsGM; )
290
291 // Lifted from https://bugs.chromium.org/p/chromium/issues/detail?id=640031
292 class TinyAngleBigRadiusArcsGM : public skiagm::GM {
293 public:
294     TinyAngleBigRadiusArcsGM() {}
295
296 protected:
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
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;
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         }
334     }
335
336 private:
337     typedef skiagm::GM INHERITED;
338 };
339 DEF_GM( return new TinyAngleBigRadiusArcsGM; )