1/*
2 * Copyright 2012 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#include "gm.h"
8#include "SkCanvas.h"
9#include "SkPaint.h"
10#include "Sk1DPathEffect.h"
11#include "Sk2DPathEffect.h"
12#include "SkCornerPathEffect.h"
13#include "SkDashPathEffect.h"
14#include "SkDiscretePathEffect.h"
15
16namespace skiagm {
17
18static void compose_pe(SkPaint* paint) {
19    SkPathEffect* pe = paint->getPathEffect();
20    sk_sp<SkPathEffect> corner = SkCornerPathEffect::Make(25);
21    sk_sp<SkPathEffect> compose;
22    if (pe) {
23        compose = SkPathEffect::MakeCompose(sk_ref_sp(pe), corner);
24    } else {
25        compose = corner;
26    }
27    paint->setPathEffect(compose);
28}
29
30static void hair_pe(SkPaint* paint) {
31    paint->setStrokeWidth(0);
32}
33
34static void hair2_pe(SkPaint* paint) {
35    paint->setStrokeWidth(0);
36    compose_pe(paint);
37}
38
39static void stroke_pe(SkPaint* paint) {
40    paint->setStrokeWidth(12);
41    compose_pe(paint);
42}
43
44static void dash_pe(SkPaint* paint) {
45    SkScalar inter[] = { 20, 10, 10, 10 };
46    paint->setStrokeWidth(12);
47    paint->setPathEffect(SkDashPathEffect::Make(inter, SK_ARRAY_COUNT(inter), 0));
48    compose_pe(paint);
49}
50
51constexpr int gXY[] = {
524, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
53};
54
55static void scale(SkPath* path, SkScalar scale) {
56    SkMatrix m;
57    m.setScale(scale, scale);
58    path->transform(m);
59}
60
61static void one_d_pe(SkPaint* paint) {
62    SkPath  path;
63    path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
64    for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
65        path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
66    path.close();
67    path.offset(SkIntToScalar(-6), 0);
68    scale(&path, 1.5f);
69
70    paint->setPathEffect(SkPath1DPathEffect::Make(path, SkIntToScalar(21), 0,
71                                                  SkPath1DPathEffect::kRotate_Style));
72    compose_pe(paint);
73}
74
75typedef void (*PE_Proc)(SkPaint*);
76constexpr PE_Proc gPE[] = { hair_pe, hair2_pe, stroke_pe, dash_pe, one_d_pe };
77
78static void fill_pe(SkPaint* paint) {
79    paint->setStyle(SkPaint::kFill_Style);
80    paint->setPathEffect(nullptr);
81}
82
83static void discrete_pe(SkPaint* paint) {
84    paint->setPathEffect(SkDiscretePathEffect::Make(10, 4));
85}
86
87static sk_sp<SkPathEffect> MakeTileEffect() {
88    SkMatrix m;
89    m.setScale(SkIntToScalar(12), SkIntToScalar(12));
90
91    SkPath path;
92    path.addCircle(0, 0, SkIntToScalar(5));
93
94    return SkPath2DPathEffect::Make(m, path);
95}
96
97static void tile_pe(SkPaint* paint) {
98    paint->setPathEffect(MakeTileEffect());
99}
100
101constexpr PE_Proc gPE2[] = { fill_pe, discrete_pe, tile_pe };
102
103class PathEffectGM : public GM {
104public:
105    PathEffectGM() {}
106
107protected:
108
109    SkString onShortName() override {
110        return SkString("patheffect");
111    }
112
113    SkISize onISize() override { return SkISize::Make(800, 600); }
114
115    void onDraw(SkCanvas* canvas) override {
116        SkPaint paint;
117        paint.setAntiAlias(true);
118        paint.setStyle(SkPaint::kStroke_Style);
119
120        SkPath path;
121        path.moveTo(20, 20);
122        path.lineTo(70, 120);
123        path.lineTo(120, 30);
124        path.lineTo(170, 80);
125        path.lineTo(240, 50);
126
127        size_t i;
128        canvas->save();
129        for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
130            gPE[i](&paint);
131            canvas->drawPath(path, paint);
132            canvas->translate(0, 75);
133        }
134        canvas->restore();
135
136        path.reset();
137        SkRect r = { 0, 0, 250, 120 };
138        path.addOval(r, SkPath::kCW_Direction);
139        r.inset(50, 50);
140        path.addRect(r, SkPath::kCCW_Direction);
141
142        canvas->translate(320, 20);
143        for (i = 0; i < SK_ARRAY_COUNT(gPE2); i++) {
144            gPE2[i](&paint);
145            canvas->drawPath(path, paint);
146            canvas->translate(0, 160);
147        }
148
149        SkIRect rect = SkIRect::MakeXYWH(20, 20, 60, 60);
150        for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
151            SkPaint p;
152            p.setAntiAlias(true);
153            p.setStyle(SkPaint::kFill_Style);
154            gPE[i](&p);
155            canvas->drawIRect(rect, p);
156            canvas->translate(75, 0);
157        }
158    }
159
160private:
161    typedef GM INHERITED;
162};
163
164//////////////////////////////////////////////////////////////////////////////
165
166static GM* PathEffectFactory(void*) { return new PathEffectGM; }
167static GMRegistry regPathEffect(PathEffectFactory);
168
169}
170