119d8f9f17373bcf7d352b77e72a6a46568ee8a8breed/*
219d8f9f17373bcf7d352b77e72a6a46568ee8a8breed * Copyright 2015 Google Inc.
319d8f9f17373bcf7d352b77e72a6a46568ee8a8breed *
419d8f9f17373bcf7d352b77e72a6a46568ee8a8breed * Use of this source code is governed by a BSD-style license that can be
519d8f9f17373bcf7d352b77e72a6a46568ee8a8breed * found in the LICENSE file.
619d8f9f17373bcf7d352b77e72a6a46568ee8a8breed */
719d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
819d8f9f17373bcf7d352b77e72a6a46568ee8a8breed#include "gm.h"
976113a9b7716748c70ea0ecf7aacbabe4cce5009reed#include "SkAnimTimer.h"
1019d8f9f17373bcf7d352b77e72a6a46568ee8a8breed#include "SkCanvas.h"
1161adb1b6491db3d3552d09a1c69ba5a37beb38d5reed#include "SkPathMeasure.h"
1219d8f9f17373bcf7d352b77e72a6a46568ee8a8breed#include "SkRandom.h"
1319d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
1419d8f9f17373bcf7d352b77e72a6a46568ee8a8breedclass AddArcGM : public skiagm::GM {
15d9adfe6a223955bc69c8c7661ab8e0a078afbc32reedpublic:
16d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed    AddArcGM() : fRotate(0) {}
17d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed
1819d8f9f17373bcf7d352b77e72a6a46568ee8a8breedprotected:
1936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkString onShortName() override { return SkString("addarc"); }
2019d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
2136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkISize onISize() override { return SkISize::Make(1040, 1040); }
2219d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
2336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDraw(SkCanvas* canvas) override {
2419d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        canvas->translate(20, 20);
2519d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
2619d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        SkRect r = SkRect::MakeWH(1000, 1000);
2719d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
2819d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        SkPaint paint;
2919d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        paint.setAntiAlias(true);
3019d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        paint.setStyle(SkPaint::kStroke_Style);
3119d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        paint.setStrokeWidth(15);
3219d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
3319d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        const SkScalar inset = paint.getStrokeWidth() + 4;
3419d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        const SkScalar sweepAngle = 345;
3519d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        SkRandom rand;
3619d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
37d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed        SkScalar sign = 1;
3819d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        while (r.width() > paint.getStrokeWidth() * 3) {
3919d8f9f17373bcf7d352b77e72a6a46568ee8a8breed            paint.setColor(rand.nextU() | (0xFF << 24));
4019d8f9f17373bcf7d352b77e72a6a46568ee8a8breed            SkScalar startAngle = rand.nextUScalar1() * 360;
4119d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
42d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed            SkScalar speed = SkScalarSqrt(16 / r.width()) * 0.5f;
43d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed            startAngle += fRotate * 360 * speed * sign;
44d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed
4519d8f9f17373bcf7d352b77e72a6a46568ee8a8breed            SkPath path;
4619d8f9f17373bcf7d352b77e72a6a46568ee8a8breed            path.addArc(r, startAngle, sweepAngle);
4719d8f9f17373bcf7d352b77e72a6a46568ee8a8breed            canvas->drawPath(path, paint);
4819d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
4919d8f9f17373bcf7d352b77e72a6a46568ee8a8breed            r.inset(inset, inset);
50d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed            sign = -sign;
5119d8f9f17373bcf7d352b77e72a6a46568ee8a8breed        }
5219d8f9f17373bcf7d352b77e72a6a46568ee8a8breed    }
5319d8f9f17373bcf7d352b77e72a6a46568ee8a8breed
5436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onAnimate(const SkAnimTimer& timer) override {
5576113a9b7716748c70ea0ecf7aacbabe4cce5009reed        fRotate = timer.scaled(1, 360);
56d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed        return true;
57d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed    }
58d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed
5919d8f9f17373bcf7d352b77e72a6a46568ee8a8breedprivate:
60d9adfe6a223955bc69c8c7661ab8e0a078afbc32reed    SkScalar fRotate;
6119d8f9f17373bcf7d352b77e72a6a46568ee8a8breed    typedef skiagm::GM INHERITED;
6219d8f9f17373bcf7d352b77e72a6a46568ee8a8breed};
6319d8f9f17373bcf7d352b77e72a6a46568ee8a8breedDEF_GM( return new AddArcGM; )
6461adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
6561adb1b6491db3d3552d09a1c69ba5a37beb38d5reed///////////////////////////////////////////////////
6661adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
6761adb1b6491db3d3552d09a1c69ba5a37beb38d5reed#define R   400
6861adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
6961adb1b6491db3d3552d09a1c69ba5a37beb38d5reedclass AddArcMeasGM : public skiagm::GM {
7061adb1b6491db3d3552d09a1c69ba5a37beb38d5reedpublic:
7161adb1b6491db3d3552d09a1c69ba5a37beb38d5reed    AddArcMeasGM() {}
7261adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
7361adb1b6491db3d3552d09a1c69ba5a37beb38d5reedprotected:
7436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkString onShortName() override { return SkString("addarc_meas"); }
7561adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
7636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkISize onISize() override { return SkISize::Make(2*R + 40, 2*R + 40); }
7761adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
7836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDraw(SkCanvas* canvas) override {
7961adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        canvas->translate(R + 20, R + 20);
8061adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
8161adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        SkPaint paint;
8261adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        paint.setAntiAlias(true);
8361adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        paint.setStyle(SkPaint::kStroke_Style);
8461adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
8561adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        SkPaint measPaint;
8661adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        measPaint.setAntiAlias(true);
8761adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        measPaint.setColor(SK_ColorRED);
8861adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
8961adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        const SkRect oval = SkRect::MakeLTRB(-R, -R, R, R);
9061adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        canvas->drawOval(oval, paint);
9161adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
9261adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        for (SkScalar deg = 0; deg < 360; deg += 10) {
9361adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            const SkScalar rad = SkDegreesToRadians(deg);
9461adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            SkScalar rx = SkScalarCos(rad) * R;
9561adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            SkScalar ry = SkScalarSin(rad) * R;
9661adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
9761adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            canvas->drawLine(0, 0, rx, ry, paint);
9861adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
9961adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            SkPath path;
10061adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            path.addArc(oval, 0, deg);
10161adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            SkPathMeasure meas(path, false);
10261adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            SkScalar arcLen = rad * R;
10361adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            SkPoint pos;
10461adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            if (meas.getPosTan(arcLen, &pos, NULL)) {
10561adb1b6491db3d3552d09a1c69ba5a37beb38d5reed                canvas->drawLine(0, 0, pos.x(), pos.y(), measPaint);
10661adb1b6491db3d3552d09a1c69ba5a37beb38d5reed            }
10761adb1b6491db3d3552d09a1c69ba5a37beb38d5reed        }
10861adb1b6491db3d3552d09a1c69ba5a37beb38d5reed    }
10961adb1b6491db3d3552d09a1c69ba5a37beb38d5reed
11061adb1b6491db3d3552d09a1c69ba5a37beb38d5reedprivate:
11161adb1b6491db3d3552d09a1c69ba5a37beb38d5reed    typedef skiagm::GM INHERITED;
11261adb1b6491db3d3552d09a1c69ba5a37beb38d5reed};
11361adb1b6491db3d3552d09a1c69ba5a37beb38d5reedDEF_GM( return new AddArcMeasGM; )
1148ed666d230231c7280069236f265a61edb8a9a20reed
1158ed666d230231c7280069236f265a61edb8a9a20reed///////////////////////////////////////////////////
1168ed666d230231c7280069236f265a61edb8a9a20reed
1178ed666d230231c7280069236f265a61edb8a9a20reed// Emphasize drawing a stroked oval (containing conics) and then scaling the results up,
1188ed666d230231c7280069236f265a61edb8a9a20reed// to ensure that we compute the stroke taking the CTM into account
1198ed666d230231c7280069236f265a61edb8a9a20reed//
1208ed666d230231c7280069236f265a61edb8a9a20reedclass StrokeCircleGM : public skiagm::GM {
1218ed666d230231c7280069236f265a61edb8a9a20reedpublic:
1228ed666d230231c7280069236f265a61edb8a9a20reed    StrokeCircleGM() : fRotate(0) {}
1238ed666d230231c7280069236f265a61edb8a9a20reed
1248ed666d230231c7280069236f265a61edb8a9a20reedprotected:
12536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkString onShortName() override { return SkString("strokecircle"); }
1268ed666d230231c7280069236f265a61edb8a9a20reed
12736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkISize onISize() override { return SkISize::Make(520, 520); }
1288ed666d230231c7280069236f265a61edb8a9a20reed
12936352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDraw(SkCanvas* canvas) override {
1308ed666d230231c7280069236f265a61edb8a9a20reed        canvas->scale(20, 20);
1318ed666d230231c7280069236f265a61edb8a9a20reed        canvas->translate(13, 13);
1328ed666d230231c7280069236f265a61edb8a9a20reed
1338ed666d230231c7280069236f265a61edb8a9a20reed        SkPaint paint;
1348ed666d230231c7280069236f265a61edb8a9a20reed        paint.setAntiAlias(true);
1358ed666d230231c7280069236f265a61edb8a9a20reed        paint.setStyle(SkPaint::kStroke_Style);
1368ed666d230231c7280069236f265a61edb8a9a20reed        paint.setStrokeWidth(SK_Scalar1 / 2);
1378ed666d230231c7280069236f265a61edb8a9a20reed
1388ed666d230231c7280069236f265a61edb8a9a20reed        const SkScalar delta = paint.getStrokeWidth() * 3 / 2;
1398ed666d230231c7280069236f265a61edb8a9a20reed        SkRect r = SkRect::MakeXYWH(-12, -12, 24, 24);
1408ed666d230231c7280069236f265a61edb8a9a20reed        SkRandom rand;
1418ed666d230231c7280069236f265a61edb8a9a20reed
1428ed666d230231c7280069236f265a61edb8a9a20reed        SkScalar sign = 1;
1438ed666d230231c7280069236f265a61edb8a9a20reed        while (r.width() > paint.getStrokeWidth() * 2) {
1448ed666d230231c7280069236f265a61edb8a9a20reed            SkAutoCanvasRestore acr(canvas, true);
1458ed666d230231c7280069236f265a61edb8a9a20reed            canvas->rotate(fRotate * sign);
1468ed666d230231c7280069236f265a61edb8a9a20reed
1478ed666d230231c7280069236f265a61edb8a9a20reed            paint.setColor(rand.nextU() | (0xFF << 24));
1488ed666d230231c7280069236f265a61edb8a9a20reed            canvas->drawOval(r, paint);
1498ed666d230231c7280069236f265a61edb8a9a20reed            r.inset(delta, delta);
1508ed666d230231c7280069236f265a61edb8a9a20reed            sign = -sign;
1518ed666d230231c7280069236f265a61edb8a9a20reed        }
1528ed666d230231c7280069236f265a61edb8a9a20reed    }
1538ed666d230231c7280069236f265a61edb8a9a20reed
15436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onAnimate(const SkAnimTimer& timer) override {
1558ed666d230231c7280069236f265a61edb8a9a20reed        fRotate = timer.scaled(60, 360);
1568ed666d230231c7280069236f265a61edb8a9a20reed        return true;
1578ed666d230231c7280069236f265a61edb8a9a20reed    }
1588ed666d230231c7280069236f265a61edb8a9a20reed
1598ed666d230231c7280069236f265a61edb8a9a20reedprivate:
1608ed666d230231c7280069236f265a61edb8a9a20reed    SkScalar fRotate;
1618ed666d230231c7280069236f265a61edb8a9a20reed
1628ed666d230231c7280069236f265a61edb8a9a20reed    typedef skiagm::GM INHERITED;
1638ed666d230231c7280069236f265a61edb8a9a20reed};
1648ed666d230231c7280069236f265a61edb8a9a20reedDEF_GM( return new StrokeCircleGM; )
1659e779d495130009926fc5394a8971eec20494e5freed
1669e779d495130009926fc5394a8971eec20494e5freed//////////////////////
1679e779d495130009926fc5394a8971eec20494e5freed
1689e779d495130009926fc5394a8971eec20494e5freedstatic void html_canvas_arc(SkPath* path, SkScalar x, SkScalar y, SkScalar r, SkScalar start,
1699e779d495130009926fc5394a8971eec20494e5freed                            SkScalar end, bool ccw) {
1709e779d495130009926fc5394a8971eec20494e5freed    SkRect bounds = { x - r, y - r, x + r, y + r };
1719e779d495130009926fc5394a8971eec20494e5freed    SkScalar sweep = ccw ? end - start : start - end;
1729e779d495130009926fc5394a8971eec20494e5freed    path->arcTo(bounds, start, sweep, false);
1739e779d495130009926fc5394a8971eec20494e5freed}
1749e779d495130009926fc5394a8971eec20494e5freed
1759e779d495130009926fc5394a8971eec20494e5freed// Lifted from canvas-arc-circumference-fill-diffs.html
1769e779d495130009926fc5394a8971eec20494e5freedclass ManyArcsGM : public skiagm::GM {
1779e779d495130009926fc5394a8971eec20494e5freedpublic:
1789e779d495130009926fc5394a8971eec20494e5freed    ManyArcsGM() {}
1799e779d495130009926fc5394a8971eec20494e5freed
1809e779d495130009926fc5394a8971eec20494e5freedprotected:
18136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkString onShortName() override { return SkString("manyarcs"); }
1829e779d495130009926fc5394a8971eec20494e5freed
18336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    SkISize onISize() override { return SkISize::Make(620, 330); }
1849e779d495130009926fc5394a8971eec20494e5freed
18536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onDraw(SkCanvas* canvas) override {
1869e779d495130009926fc5394a8971eec20494e5freed        SkPaint paint;
1879e779d495130009926fc5394a8971eec20494e5freed        paint.setAntiAlias(true);
1889e779d495130009926fc5394a8971eec20494e5freed        paint.setStyle(SkPaint::kStroke_Style);
1899e779d495130009926fc5394a8971eec20494e5freed
1909e779d495130009926fc5394a8971eec20494e5freed        canvas->translate(10, 10);
1919e779d495130009926fc5394a8971eec20494e5freed
1929e779d495130009926fc5394a8971eec20494e5freed        // 20 angles.
1939e779d495130009926fc5394a8971eec20494e5freed        SkScalar sweepAngles[] = {
1949e779d495130009926fc5394a8971eec20494e5freed                           -123.7f, -2.3f, -2, -1, -0.3f, -0.000001f, 0, 0.000001f, 0.3f, 0.7f,
1959e779d495130009926fc5394a8971eec20494e5freed                           1, 1.3f, 1.5f, 1.7f, 1.99999f, 2, 2.00001f, 2.3f, 4.3f, 3934723942837.3f
1969e779d495130009926fc5394a8971eec20494e5freed        };
1979e779d495130009926fc5394a8971eec20494e5freed        for (size_t i = 0; i < SK_ARRAY_COUNT(sweepAngles); ++i) {
1989e779d495130009926fc5394a8971eec20494e5freed            sweepAngles[i] *= 180;
1999e779d495130009926fc5394a8971eec20494e5freed        }
2009e779d495130009926fc5394a8971eec20494e5freed
2019e779d495130009926fc5394a8971eec20494e5freed        SkScalar startAngles[] = { -1, -0.5f, 0, 0.5f };
2029e779d495130009926fc5394a8971eec20494e5freed        for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles); ++i) {
2039e779d495130009926fc5394a8971eec20494e5freed            startAngles[i] *= 180;
2049e779d495130009926fc5394a8971eec20494e5freed        }
2059e779d495130009926fc5394a8971eec20494e5freed
2069e779d495130009926fc5394a8971eec20494e5freed        bool anticlockwise = false;
2079e779d495130009926fc5394a8971eec20494e5freed        SkScalar sign = 1;
2089e779d495130009926fc5394a8971eec20494e5freed        for (size_t i = 0; i < SK_ARRAY_COUNT(startAngles) * 2; ++i) {
2099e779d495130009926fc5394a8971eec20494e5freed            if (i == SK_ARRAY_COUNT(startAngles)) {
2109e779d495130009926fc5394a8971eec20494e5freed                anticlockwise = true;
2119e779d495130009926fc5394a8971eec20494e5freed                sign = -1;
2129e779d495130009926fc5394a8971eec20494e5freed            }
2139e779d495130009926fc5394a8971eec20494e5freed            SkScalar startAngle = startAngles[i % SK_ARRAY_COUNT(startAngles)] * sign;
2149e779d495130009926fc5394a8971eec20494e5freed            canvas->save();
2159e779d495130009926fc5394a8971eec20494e5freed            for (size_t j = 0; j < SK_ARRAY_COUNT(sweepAngles); ++j) {
2169e779d495130009926fc5394a8971eec20494e5freed                SkPath path;
2179e779d495130009926fc5394a8971eec20494e5freed                path.moveTo(0, 2);
2189e779d495130009926fc5394a8971eec20494e5freed                html_canvas_arc(&path, 18, 15, 10, startAngle, startAngle + (sweepAngles[j] * sign),
2199e779d495130009926fc5394a8971eec20494e5freed                                anticlockwise);
2209e779d495130009926fc5394a8971eec20494e5freed                path.lineTo(0, 28);
2219e779d495130009926fc5394a8971eec20494e5freed                canvas->drawPath(path, paint);
2229e779d495130009926fc5394a8971eec20494e5freed                canvas->translate(30, 0);
2239e779d495130009926fc5394a8971eec20494e5freed            }
2249e779d495130009926fc5394a8971eec20494e5freed            canvas->restore();
2259e779d495130009926fc5394a8971eec20494e5freed            canvas->translate(0, 40);
2269e779d495130009926fc5394a8971eec20494e5freed        }
2279e779d495130009926fc5394a8971eec20494e5freed    }
2289e779d495130009926fc5394a8971eec20494e5freed
2299e779d495130009926fc5394a8971eec20494e5freedprivate:
2309e779d495130009926fc5394a8971eec20494e5freed    typedef skiagm::GM INHERITED;
2319e779d495130009926fc5394a8971eec20494e5freed};
2329e779d495130009926fc5394a8971eec20494e5freedDEF_GM( return new ManyArcsGM; )
2339e779d495130009926fc5394a8971eec20494e5freed
234