Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
patheffects.cpp
Go to the documentation of this file.
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"
14#include "include/core/SkRect.h"
17#include "include/core/SkSize.h"
27
28#include <initializer_list>
29
30namespace skiagm {
31
32static void compose_pe(SkPaint* paint) {
33 SkPathEffect* pe = paint->getPathEffect();
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
44static void hair_pe(SkPaint* paint) {
45 paint->setStrokeWidth(0);
46}
47
48static void hair2_pe(SkPaint* paint) {
49 paint->setStrokeWidth(0);
51}
52
53static void stroke_pe(SkPaint* paint) {
54 paint->setStrokeWidth(12);
56}
57
58static void dash_pe(SkPaint* paint) {
59 SkScalar inter[] = { 20, 10, 10, 10 };
60 paint->setStrokeWidth(12);
61 paint->setPathEffect(SkDashPathEffect::Make(inter, std::size(inter), 0));
63}
64
65constexpr int gXY[] = {
664, 0, 0, -4, 8, -4, 12, 0, 8, 4, 0, 4
67};
68
69static SkPath scale(const SkPath& path, SkScalar scale) {
70 SkMatrix m;
71 m.setScale(scale, scale);
72 return path.makeTransform(m);
73}
74
75static void one_d_pe(SkPaint* paint) {
78 for (unsigned i = 2; i < std::size(gXY); i += 2) {
80 }
81 b.close().offset(SkIntToScalar(-6), 0);
82 SkPath path = scale(b.detach(), 1.5f);
83
84 paint->setPathEffect(SkPath1DPathEffect::Make(path, SkIntToScalar(21), 0,
87}
88
89typedef void (*PE_Proc)(SkPaint*);
91
92static void fill_pe(SkPaint* paint) {
93 paint->setStyle(SkPaint::kFill_Style);
94 paint->setPathEffect(nullptr);
95}
96
97static void discrete_pe(SkPaint* paint) {
98 paint->setPathEffect(SkDiscretePathEffect::Make(10, 4));
99}
100
102 SkMatrix m;
103 m.setScale(SkIntToScalar(12), SkIntToScalar(12));
104
106}
107
108static void tile_pe(SkPaint* paint) {
109 paint->setPathEffect(MakeTileEffect());
110}
111
113
114class PathEffectGM : public GM {
115public:
117
118protected:
119 SkString getName() const override { return SkString("patheffect"); }
120
121 SkISize getISize() override { return SkISize::Make(800, 600); }
122
123 void onDraw(SkCanvas* canvas) override {
125 paint.setAntiAlias(true);
127
128 SkPath path = SkPath::Polygon({
129 {20, 20},
130 {70, 120},
131 {120, 30},
132 {170, 80},
133 {240, 50},
134 }, false);
135
136 canvas->save();
137 for (size_t i = 0; i < std::size(gPE); i++) {
138 gPE[i](&paint);
139 canvas->drawPath(path, paint);
140 canvas->translate(0, 75);
141 }
142 canvas->restore();
143
144 path.reset();
145 SkRect r = { 0, 0, 250, 120 };
148 .detach();
149
150 canvas->translate(320, 20);
151 for (size_t i = 0; i < std::size(gPE2); i++) {
152 gPE2[i](&paint);
153 canvas->drawPath(path, paint);
154 canvas->translate(0, 160);
155 }
156
157 const SkIRect rect = SkIRect::MakeXYWH(20, 20, 60, 60);
158 for (size_t i = 0; i < std::size(gPE); i++) {
159 SkPaint p;
160 p.setAntiAlias(true);
161 p.setStyle(SkPaint::kFill_Style);
162 gPE[i](&p);
163 canvas->drawIRect(rect, p);
164 canvas->translate(75, 0);
165 }
166 }
167
168private:
169 using INHERITED = GM;
170};
171
172DEF_GM( return new PathEffectGM; )
173
174} // namespace skiagm
175
176//////////////////////////////////////////////////////////////////////////////
177
180
181namespace {
182/**
183 * Example path effect using CTM. This "strokes" a single line segment with some stroke width,
184 * and then inflates the result by some number of pixels.
185 */
186class StrokeLineInflated : public SkPathEffectBase {
187public:
188 StrokeLineInflated(float strokeWidth, float pxInflate)
189 : fRadius(strokeWidth / 2.f), fPxInflate(pxInflate) {}
190
191 bool onNeedsCTM() const final { return true; }
192
193 bool onFilterPath(SkPath* dst,
194 const SkPath& src,
195 SkStrokeRec* rec,
196 const SkRect* cullR,
197 const SkMatrix& ctm) const final {
198 SkASSERT(src.countPoints() == 2);
199 const SkPoint pts[2] = {src.getPoint(0), src.getPoint(1)};
200
201 SkMatrix invCtm;
202 if (!ctm.invert(&invCtm)) {
203 return false;
204 }
205
206 // For a line segment, we can just map the (scaled) normal vector to pixel-space,
207 // increase its length by the desired number of pixels, and then map back to canvas space.
208 SkPoint n = {pts[0].fY - pts[1].fY, pts[1].fX - pts[0].fX};
209 if (!n.setLength(fRadius)) {
210 return false;
211 }
212
213 SkPoint mappedN = ctm.mapVector(n.fX, n.fY);
214 if (!mappedN.setLength(mappedN.length() + fPxInflate)) {
215 return false;
216 }
217 n = invCtm.mapVector(mappedN.fX, mappedN.fY);
218
219 dst->moveTo(pts[0] + n);
220 dst->lineTo(pts[1] + n);
221 dst->lineTo(pts[1] - n);
222 dst->lineTo(pts[0] - n);
223 dst->close();
224
225 rec->setFillStyle();
226
227 return true;
228 }
229
230protected:
231 void flatten(SkWriteBuffer&) const final {}
232
233private:
234 SK_FLATTENABLE_HOOKS(StrokeLineInflated)
235
236 bool computeFastBounds(SkRect* bounds) const final { return false; }
237
238 const float fRadius;
239 const float fPxInflate;
240};
241
242sk_sp<SkFlattenable> StrokeLineInflated::CreateProc(SkReadBuffer&) { return nullptr; }
243
244} // namespace
245
247protected:
248 SkString getName() const override { return SkString("ctmpatheffect"); }
249
250 SkISize getISize() override { return SkISize::Make(800, 600); }
251
252 // TODO: ctm-aware path effects are currently CPU only
254 auto dctx = GrAsDirectContext(canvas->recordingContext());
255 return dctx == nullptr ? DrawResult::kOk : DrawResult::kSkip;
256 }
257
258 void onDraw(SkCanvas* canvas) override {
259 const float strokeWidth = 16;
260 const float pxInflate = 0.5f;
261 sk_sp<SkPathEffect> pathEffect(new StrokeLineInflated(strokeWidth, pxInflate));
262
263 SkPath path;
264 path.moveTo(100, 100);
265 path.lineTo(200, 200);
266
267 // Draw the inflated path, and a scaled version, in blue.
269 paint.setAntiAlias(true);
270 paint.setColor(SkColorSetA(SK_ColorBLUE, 0xff));
271 paint.setPathEffect(pathEffect);
272 canvas->drawPath(path, paint);
273 canvas->save();
274 canvas->translate(150, 0);
275 canvas->scale(2.5, 0.5f);
276 canvas->drawPath(path, paint);
277 canvas->restore();
278
279 // Draw the regular stroked version on top in green.
280 // The inflated version should be visible underneath as a blue "border".
281 paint.setPathEffect(nullptr);
283 paint.setStrokeWidth(strokeWidth);
284 paint.setColor(SkColorSetA(SK_ColorGREEN, 0xff));
285 canvas->drawPath(path, paint);
286 canvas->save();
287 canvas->translate(150, 0);
288 canvas->scale(2.5, 0.5f);
289 canvas->drawPath(path, paint);
290 canvas->restore();
291 }
292
293private:
294 using INHERITED = GM;
295};
296DEF_GM(return new CTMPathEffectGM;)
static const int strokeWidth
Definition BlurTest.cpp:60
static GrDirectContext * GrAsDirectContext(GrContext_Base *base)
#define SkASSERT(cond)
Definition SkAssert.h:116
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
static constexpr SkColor SkColorSetA(SkColor c, U8CPU a)
Definition SkColor.h:82
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
#define SK_FLATTENABLE_HOOKS(type)
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
#define SkIntToScalar(x)
Definition SkScalar.h:57
SkISize getISize() override
DrawResult onGpuSetup(SkCanvas *canvas, SkString *, GraphiteTestContext *) override
SkString getName() const override
void onDraw(SkCanvas *canvas) override
void restore()
Definition SkCanvas.cpp:465
void translate(SkScalar dx, SkScalar dy)
virtual GrRecordingContext * recordingContext() const
void drawIRect(const SkIRect &rect, const SkPaint &paint)
Definition SkCanvas.h:1358
int save()
Definition SkCanvas.cpp:451
void drawPath(const SkPath &path, const SkPaint &paint)
void scale(SkScalar sx, SkScalar sy)
static sk_sp< SkPathEffect > Make(SkScalar radius)
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
static sk_sp< SkPathEffect > Make(SkScalar segLength, SkScalar dev, uint32_t seedAssist=0)
virtual void flatten(SkWriteBuffer &) const
void mapVector(SkScalar dx, SkScalar dy, SkVector *result) const
Definition SkMatrix.h:1524
@ kStroke_Style
set to stroke geometry
Definition SkPaint.h:194
@ kFill_Style
set to fill geometry
Definition SkPaint.h:193
static sk_sp< SkPathEffect > Make(const SkPath &path, SkScalar advance, SkScalar phase, Style)
static sk_sp< SkPathEffect > Make(const SkMatrix &matrix, const SkPath &path)
SkPathBuilder & close()
SkPathBuilder & lineTo(SkPoint pt)
SkPathBuilder & addRect(const SkRect &, SkPathDirection, unsigned startIndex)
SkPathBuilder & moveTo(SkPoint pt)
SkPathBuilder & addOval(const SkRect &, SkPathDirection, unsigned startIndex)
SkPathBuilder & offset(SkScalar dx, SkScalar dy)
virtual bool onNeedsCTM() const
virtual bool computeFastBounds(SkRect *bounds) const =0
virtual bool onFilterPath(SkPath *, const SkPath &, SkStrokeRec *, const SkRect *, const SkMatrix &) const =0
static sk_sp< SkPathEffect > MakeCompose(sk_sp< SkPathEffect > outer, sk_sp< SkPathEffect > inner)
static SkPath Circle(SkScalar center_x, SkScalar center_y, SkScalar radius, SkPathDirection dir=SkPathDirection::kCW)
Definition SkPath.cpp:3530
static SkPath Polygon(const SkPoint pts[], int count, bool isClosed, SkPathFillType=SkPathFillType::kWinding, bool isVolatile=false)
Definition SkPath.cpp:3546
GM(SkColor backgroundColor=SK_ColorWHITE)
Definition gm.cpp:81
void onDraw(SkCanvas *canvas) override
SkString getName() const override
SkISize getISize() override
const Paint & paint
float SkScalar
Definition extension.cpp:12
static bool b
#define DEF_GM(CODE)
Definition gm.h:40
dst
Definition cp.py:12
void(* PE_Proc)(SkPaint *)
constexpr PE_Proc gPE[]
static void hair_pe(SkPaint *paint)
static void compose_pe(SkPaint *paint)
static void one_d_pe(SkPaint *paint)
static void dash_pe(SkPaint *paint)
constexpr PE_Proc gPE2[]
static void hair2_pe(SkPaint *paint)
static sk_sp< SkPathEffect > MakeTileEffect()
static void fill_pe(SkPaint *paint)
static void tile_pe(SkPaint *paint)
constexpr int gXY[]
static void discrete_pe(SkPaint *paint)
static void stroke_pe(SkPaint *paint)
DrawResult
Definition gm.h:104
const Scalar scale
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
bool setLength(float length)
Definition SkPoint.cpp:30
float fX
x-axis value
float length() const
float fY
y-axis value
SkRect makeInset(float dx, float dy) const
Definition SkRect.h:987