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
8 #include "gm/gm.h"
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkMatrix.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPath.h"
13 #include "include/core/SkPathEffect.h"
14 #include "include/core/SkRect.h"
15 #include "include/core/SkRefCnt.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/effects/Sk1DPathEffect.h"
21 #include "include/effects/Sk2DPathEffect.h"
22 #include "include/effects/SkCornerPathEffect.h"
23 #include "include/effects/SkDashPathEffect.h"
24 #include "include/effects/SkDiscretePathEffect.h"
25 #include "include/effects/SkOpPathEffect.h"
26 #include "include/pathops/SkPathOps.h"
27
28 #include <initializer_list>
29
30 namespace skiagm {
31
compose_pe(SkPaint * paint)32 static void compose_pe(SkPaint* paint) {
33 SkPathEffect* pe = paint->getPathEffect();
34 sk_sp<SkPathEffect> corner = SkCornerPathEffect::Make(25);
35 sk_sp<SkPathEffect> compose;
36 if (pe) {
37 compose = SkPathEffect::MakeCompose(sk_ref_sp(pe), corner);
38 } else {
39 compose = corner;
40 }
41 paint->setPathEffect(compose);
42 }
43
hair_pe(SkPaint * paint)44 static void hair_pe(SkPaint* paint) {
45 paint->setStrokeWidth(0);
46 }
47
hair2_pe(SkPaint * paint)48 static void hair2_pe(SkPaint* paint) {
49 paint->setStrokeWidth(0);
50 compose_pe(paint);
51 }
52
stroke_pe(SkPaint * paint)53 static void stroke_pe(SkPaint* paint) {
54 paint->setStrokeWidth(12);
55 compose_pe(paint);
56 }
57
dash_pe(SkPaint * paint)58 static void dash_pe(SkPaint* paint) {
59 SkScalar inter[] = { 20, 10, 10, 10 };
60 paint->setStrokeWidth(12);
61 paint->setPathEffect(SkDashPathEffect::Make(inter, SK_ARRAY_COUNT(inter), 0));
62 compose_pe(paint);
63 }
64
65 constexpr int gXY[] = {
66 4, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
67 };
68
scale(SkPath * path,SkScalar scale)69 static void scale(SkPath* path, SkScalar scale) {
70 SkMatrix m;
71 m.setScale(scale, scale);
72 path->transform(m);
73 }
74
one_d_pe(SkPaint * paint)75 static void one_d_pe(SkPaint* paint) {
76 SkPath path;
77 path.moveTo(SkIntToScalar(gXY[0]), SkIntToScalar(gXY[1]));
78 for (unsigned i = 2; i < SK_ARRAY_COUNT(gXY); i += 2)
79 path.lineTo(SkIntToScalar(gXY[i]), SkIntToScalar(gXY[i+1]));
80 path.close();
81 path.offset(SkIntToScalar(-6), 0);
82 scale(&path, 1.5f);
83
84 paint->setPathEffect(SkPath1DPathEffect::Make(path, SkIntToScalar(21), 0,
85 SkPath1DPathEffect::kRotate_Style));
86 compose_pe(paint);
87 }
88
89 typedef void (*PE_Proc)(SkPaint*);
90 constexpr PE_Proc gPE[] = { hair_pe, hair2_pe, stroke_pe, dash_pe, one_d_pe };
91
fill_pe(SkPaint * paint)92 static void fill_pe(SkPaint* paint) {
93 paint->setStyle(SkPaint::kFill_Style);
94 paint->setPathEffect(nullptr);
95 }
96
discrete_pe(SkPaint * paint)97 static void discrete_pe(SkPaint* paint) {
98 paint->setPathEffect(SkDiscretePathEffect::Make(10, 4));
99 }
100
MakeTileEffect()101 static sk_sp<SkPathEffect> MakeTileEffect() {
102 SkMatrix m;
103 m.setScale(SkIntToScalar(12), SkIntToScalar(12));
104
105 SkPath path;
106 path.addCircle(0, 0, SkIntToScalar(5));
107
108 return SkPath2DPathEffect::Make(m, path);
109 }
110
tile_pe(SkPaint * paint)111 static void tile_pe(SkPaint* paint) {
112 paint->setPathEffect(MakeTileEffect());
113 }
114
115 constexpr PE_Proc gPE2[] = { fill_pe, discrete_pe, tile_pe };
116
117 class PathEffectGM : public GM {
118 public:
PathEffectGM()119 PathEffectGM() {}
120
121 protected:
122
onShortName()123 SkString onShortName() override {
124 return SkString("patheffect");
125 }
126
onISize()127 SkISize onISize() override { return SkISize::Make(800, 600); }
128
onDraw(SkCanvas * canvas)129 void onDraw(SkCanvas* canvas) override {
130 SkPaint paint;
131 paint.setAntiAlias(true);
132 paint.setStyle(SkPaint::kStroke_Style);
133
134 SkPath path;
135 path.moveTo(20, 20);
136 path.lineTo(70, 120);
137 path.lineTo(120, 30);
138 path.lineTo(170, 80);
139 path.lineTo(240, 50);
140
141 canvas->save();
142 for (size_t i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
143 gPE[i](&paint);
144 canvas->drawPath(path, paint);
145 canvas->translate(0, 75);
146 }
147 canvas->restore();
148
149 path.reset();
150 SkRect r = { 0, 0, 250, 120 };
151 path.addOval(r, SkPath::kCW_Direction);
152 r.inset(50, 50);
153 path.addRect(r, SkPath::kCCW_Direction);
154
155 canvas->translate(320, 20);
156 for (size_t i = 0; i < SK_ARRAY_COUNT(gPE2); i++) {
157 gPE2[i](&paint);
158 canvas->drawPath(path, paint);
159 canvas->translate(0, 160);
160 }
161
162 const SkIRect rect = SkIRect::MakeXYWH(20, 20, 60, 60);
163 for (size_t i = 0; i < SK_ARRAY_COUNT(gPE); i++) {
164 SkPaint p;
165 p.setAntiAlias(true);
166 p.setStyle(SkPaint::kFill_Style);
167 gPE[i](&p);
168 canvas->drawIRect(rect, p);
169 canvas->translate(75, 0);
170 }
171 }
172
173 private:
174 typedef GM INHERITED;
175 };
176
177 DEF_GM( return new PathEffectGM; )
178
179 }
180
181 //////////////////////////////////////////////////////////////////////////////
182
183 class ComboPathEfectsGM : public skiagm::GM {
184 public:
ComboPathEfectsGM()185 ComboPathEfectsGM() {}
186
187 protected:
188
onShortName()189 SkString onShortName() override {
190 return SkString("combo-patheffects");
191 }
192
onISize()193 SkISize onISize() override { return SkISize::Make(360, 630); }
194
onDraw(SkCanvas * canvas)195 void onDraw(SkCanvas* canvas) override {
196 SkPath path0, path1, path2;
197 path0.addCircle(100, 100, 60);
198 path1.moveTo(20, 20); path1.cubicTo(20, 180, 140, 0, 140, 140);
199
200 sk_sp<SkPathEffect> effects[] = {
201 nullptr,
202 SkStrokePathEffect::Make(20, SkPaint::kRound_Join, SkPaint::kRound_Cap, 0),
203 SkMergePathEffect::Make(nullptr,
204 SkStrokePathEffect::Make(20, SkPaint::kRound_Join,
205 SkPaint::kRound_Cap, 0),
206 kDifference_SkPathOp),
207 SkMergePathEffect::Make(SkMatrixPathEffect::MakeTranslate(50, 30),
208 SkStrokePathEffect::Make(20, SkPaint::kRound_Join,
209 SkPaint::kRound_Cap, 0),
210 kReverseDifference_SkPathOp),
211 };
212
213 SkPaint wireframe;
214 wireframe.setStyle(SkPaint::kStroke_Style);
215 wireframe.setAntiAlias(true);
216
217 SkPaint paint;
218 paint.setColor(0xFF8888FF);
219 paint.setAntiAlias(true);
220
221 for (auto& path : { path0, path1 }) {
222 canvas->save();
223 for (auto pe : effects) {
224 paint.setPathEffect(pe);
225 canvas->drawPath(path, paint);
226 canvas->drawPath(path, wireframe);
227
228 canvas->translate(0, 150);
229 }
230 canvas->restore();
231 canvas->translate(180, 0);
232 }
233 }
234
235 private:
236 typedef GM INHERITED;
237 };
238 DEF_GM(return new ComboPathEfectsGM;)
239
240