1/*
2 * Copyright 2016 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 "SkAnimTimer.h"
10#include "SkPath.h"
11#include "SkDashPathEffect.h"
12
13int dash1[] = { 1, 1 };
14int dash2[] = { 1, 3 };
15int dash3[] = { 1, 1, 3, 3 };
16int dash4[] = { 1, 3, 2, 4 };
17
18struct DashExample {
19    int* pattern;
20    int length;
21} dashExamples[] = {
22    { dash1, SK_ARRAY_COUNT(dash1) },
23    { dash2, SK_ARRAY_COUNT(dash2) },
24    { dash3, SK_ARRAY_COUNT(dash3) },
25    { dash4, SK_ARRAY_COUNT(dash4) }
26};
27
28
29class DashCircleGM : public skiagm::GM {
30public:
31    DashCircleGM() : fRotation(0) { }
32
33protected:
34    SkString onShortName() override { return SkString("dashcircle"); }
35
36    SkISize onISize() override { return SkISize::Make(900, 1200); }
37
38    void onDraw(SkCanvas* canvas) override {
39        SkPaint refPaint;
40        refPaint.setAntiAlias(true);
41        refPaint.setColor(0xFFbf3f7f);
42        refPaint.setStyle(SkPaint::kStroke_Style);
43        refPaint.setStrokeWidth(1);
44        const SkScalar radius = 125;
45        SkRect oval = SkRect::MakeLTRB(-radius - 20, -radius - 20, radius + 20, radius + 20);
46        SkPath circle;
47        circle.addCircle(0, 0, radius);
48        SkScalar circumference = radius * SK_ScalarPI * 2;
49        int wedges[] = { 6, 12, 36 };
50        canvas->translate(radius+20, radius+20);
51        for (int wedge : wedges) {
52            SkScalar arcLength = 360.f / wedge;
53            canvas->save();
54            for (const DashExample& dashExample : dashExamples) {
55                SkPath refPath;
56                int dashUnits = 0;
57                for (int index = 0; index < dashExample.length; ++index) {
58                    dashUnits += dashExample.pattern[index];
59                }
60                SkScalar unitLength = arcLength / dashUnits;
61                SkScalar angle = 0;
62                for (int index = 0; index < wedge; ++index) {
63                    for (int i2 = 0; i2 < dashExample.length; i2 += 2) {
64                        SkScalar span = dashExample.pattern[i2] * unitLength;
65                        refPath.moveTo(0, 0);
66                        refPath.arcTo(oval, angle, span, false);
67                        refPath.close();
68                        angle += span + (dashExample.pattern[i2 + 1]) * unitLength;
69                    }
70                }
71                canvas->save();
72                canvas->rotate(fRotation);
73                canvas->drawPath(refPath, refPaint);
74                canvas->restore();
75                SkPaint p;
76                p.setAntiAlias(true);
77                p.setStyle(SkPaint::kStroke_Style);
78                p.setStrokeWidth(10);
79                SkScalar intervals[4];
80                int intervalCount = dashExample.length;
81                SkScalar dashLength = circumference / wedge / dashUnits;
82                for (int index = 0; index < dashExample.length; ++index) {
83                    intervals[index] = dashExample.pattern[index] * dashLength;
84                }
85                p.setPathEffect(SkDashPathEffect::Make(intervals, intervalCount, 0));
86                canvas->save();
87                canvas->rotate(fRotation);
88                canvas->drawPath(circle, p);
89                canvas->restore();
90                canvas->translate(0, radius * 2 + 50);
91            }
92            canvas->restore();
93            canvas->translate(radius * 2 + 50, 0);
94        }
95    }
96
97    bool onAnimate(const SkAnimTimer& timer) override {
98        constexpr SkScalar kDesiredDurationSecs = 100.0f;
99
100        fRotation = timer.scaled(360.0f/kDesiredDurationSecs, 360.0f);
101        return true;
102    }
103
104private:
105    SkScalar fRotation;
106
107    typedef GM INHERITED;
108};
109
110DEF_GM(return new DashCircleGM; )
111