Flutter Engine
The Flutter Engine
Sk1DPathEffect.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2006 The Android Open Source Project
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
9
12#include "include/core/SkPath.h"
24
25struct SkRect;
26
27// Since we are stepping by a float, the do/while loop might go on forever (or nearly so).
28// Put in a governor to limit crash values from looping too long (and allocating too much ram).
29#define MAX_REASONABLE_ITERATIONS 100000
30
32public:
33protected:
35 const SkMatrix&) const override {
36 SkPathMeasure meas(src, false);
37 do {
38 int governor = MAX_REASONABLE_ITERATIONS;
39 SkScalar length = meas.getLength();
40 SkScalar distance = this->begin(length);
41 while (distance < length && --governor >= 0) {
42 SkScalar delta = this->next(dst, distance, meas);
43 if (delta <= 0) {
44 break;
45 }
46 distance += delta;
47 }
48 if (governor < 0) {
49 return false;
50 }
51 } while (meas.nextContour());
52 return true;
53 }
54
55 /** Called at the start of each contour, returns the initial offset
56 into that contour.
57 */
58 virtual SkScalar begin(SkScalar contourLength) const = 0;
59 /** Called with the current distance along the path, with the current matrix
60 for the point/tangent at the specified distance.
61 Return the distance to travel for the next call. If return <= 0, then that
62 contour is done.
63 */
64 virtual SkScalar next(SkPath* dst, SkScalar dist, SkPathMeasure&) const = 0;
65
66private:
67 // For simplicity, assume fast bounds cannot be computed
68 bool computeFastBounds(SkRect*) const override { return false; }
69};
70
71///////////////////////////////////////////////////////////////////////////////
72
74public:
76 SkPath1DPathEffect::Style style) : fPath(path) {
77 SkASSERT(advance > 0 && !path.isEmpty());
78
79 // Make the path thread-safe.
80 fPath.updateBoundsCache();
81 (void)fPath.getGenerationID();
82
83 // cleanup their phase parameter, inverting it so that it becomes an
84 // offset along the path (to match the interpretation in PostScript)
85 if (phase < 0) {
86 phase = -phase;
87 if (phase > advance) {
88 phase = SkScalarMod(phase, advance);
89 }
90 } else {
91 if (phase > advance) {
92 phase = SkScalarMod(phase, advance);
93 }
94 phase = advance - phase;
95 }
96 // now catch the edge case where phase == advance (within epsilon)
97 if (phase >= advance) {
98 phase = 0;
99 }
100 SkASSERT(phase >= 0);
101
102 fAdvance = advance;
103 fInitialOffset = phase;
104 fStyle = style;
105 }
106
108 const SkRect* cullRect, const SkMatrix& ctm) const override {
109 rec->setFillStyle();
110 return this->INHERITED::onFilterPath(dst, src, rec, cullRect, ctm);
111 }
112
113 SkScalar begin(SkScalar contourLength) const override {
114 return fInitialOffset;
115 }
116
117 SkScalar next(SkPath*, SkScalar, SkPathMeasure&) const override;
118
120 SkScalar advance = buffer.readScalar();
121 SkPath path;
122 buffer.readPath(&path);
123 SkScalar phase = buffer.readScalar();
125 return buffer.isValid() ? SkPath1DPathEffect::Make(path, advance, phase, style) : nullptr;
126 }
127
128 void flatten(SkWriteBuffer& buffer) const override {
129 buffer.writeScalar(fAdvance);
130 buffer.writePath(fPath);
131 buffer.writeScalar(fInitialOffset);
132 buffer.writeUInt(fStyle);
133 }
134
135 Factory getFactory() const override { return CreateProc; }
136 const char* getTypeName() const override { return "SkPath1DPathEffect"; }
137
138private:
139 SkPath fPath; // copied from constructor
140 SkScalar fAdvance; // copied from constructor
141 SkScalar fInitialOffset; // computed from phase
142 SkPath1DPathEffect::Style fStyle; // copied from constructor
143
144 using INHERITED = Sk1DPathEffect;
145};
146
147static bool morphpoints(SkPoint dst[], const SkPoint src[], int count,
148 SkPathMeasure& meas, SkScalar dist) {
149 for (int i = 0; i < count; i++) {
150 SkPoint pos;
151 SkVector tangent;
152
153 SkScalar sx = src[i].fX;
154 SkScalar sy = src[i].fY;
155
156 if (!meas.getPosTan(dist + sx, &pos, &tangent)) {
157 return false;
158 }
159
161 SkPoint pt;
162
163 pt.set(sx, sy);
164 matrix.setSinCos(tangent.fY, tangent.fX, 0, 0);
165 matrix.preTranslate(-sx, 0);
166 matrix.postTranslate(pos.fX, pos.fY);
167 matrix.mapPoints(&dst[i], &pt, 1);
168 }
169 return true;
170}
171
172/* TODO
173
174Need differentially more subdivisions when the follow-path is curvy. Not sure how to
175determine that, but we need it. I guess a cheap answer is let the caller tell us,
176but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
177*/
178static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
179 SkScalar dist) {
180 SkPath::Iter iter(src, false);
181 SkPoint srcP[4], dstP[3];
182 SkPath::Verb verb;
183
184 while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) {
185 switch (verb) {
187 if (morphpoints(dstP, srcP, 1, meas, dist)) {
188 dst->moveTo(dstP[0]);
189 }
190 break;
192 srcP[2] = srcP[1];
193 srcP[1].set(SkScalarAve(srcP[0].fX, srcP[2].fX),
194 SkScalarAve(srcP[0].fY, srcP[2].fY));
195 [[fallthrough]];
197 if (morphpoints(dstP, &srcP[1], 2, meas, dist)) {
198 dst->quadTo(dstP[0], dstP[1]);
199 }
200 break;
202 if (morphpoints(dstP, &srcP[1], 2, meas, dist)) {
203 dst->conicTo(dstP[0], dstP[1], iter.conicWeight());
204 }
205 break;
207 if (morphpoints(dstP, &srcP[1], 3, meas, dist)) {
208 dst->cubicTo(dstP[0], dstP[1], dstP[2]);
209 }
210 break;
212 dst->close();
213 break;
214 default:
215 SkDEBUGFAIL("unknown verb");
216 break;
217 }
218 }
219}
220
222 SkPathMeasure& meas) const {
223#if defined(SK_BUILD_FOR_FUZZER)
224 if (dst->countPoints() > 100000) {
225 return fAdvance;
226 }
227#endif
228 switch (fStyle) {
230 SkPoint pos;
231 if (meas.getPosTan(distance, &pos, nullptr)) {
232 dst->addPath(fPath, pos.fX, pos.fY);
233 }
234 } break;
237 if (meas.getMatrix(distance, &matrix)) {
238 dst->addPath(fPath, matrix);
239 }
240 } break;
242 morphpath(dst, fPath, meas, distance);
243 break;
244 }
245 return fAdvance;
246}
247
248///////////////////////////////////////////////////////////////////////////////////////////////////
249
251 Style style) {
252 if (advance <= 0 || !SkIsFinite(advance, phase) || path.isEmpty()) {
253 return nullptr;
254 }
255 return sk_sp<SkPathEffect>(new SkPath1DPathEffectImpl(path, advance, phase, style));
256}
257
260}
int count
Definition: FontMgrTest.cpp:50
SkPoint pos
static bool morphpoints(SkPoint dst[], const SkPoint src[], int count, SkPathMeasure &meas, SkScalar dist)
static void morphpath(SkPath *dst, const SkPath &src, SkPathMeasure &meas, SkScalar dist)
#define MAX_REASONABLE_ITERATIONS
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define SK_REGISTER_FLATTENABLE(type)
static bool SkIsFinite(T x, Pack... values)
#define SkScalarMod(x, y)
Definition: SkScalar.h:41
#define SkScalarAve(a, b)
Definition: SkScalar.h:74
virtual SkScalar next(SkPath *dst, SkScalar dist, SkPathMeasure &) const =0
bool onFilterPath(SkPath *dst, const SkPath &src, SkStrokeRec *, const SkRect *, const SkMatrix &) const override
virtual SkScalar begin(SkScalar contourLength) const =0
sk_sp< SkFlattenable >(* Factory)(SkReadBuffer &)
Definition: SkFlattenable.h:41
SkPath1DPathEffectImpl(const SkPath &path, SkScalar advance, SkScalar phase, SkPath1DPathEffect::Style style)
void flatten(SkWriteBuffer &buffer) const override
SkScalar next(SkPath *, SkScalar, SkPathMeasure &) const override
const char * getTypeName() const override
bool onFilterPath(SkPath *dst, const SkPath &src, SkStrokeRec *rec, const SkRect *cullRect, const SkMatrix &ctm) const override
static sk_sp< SkFlattenable > CreateProc(SkReadBuffer &buffer)
Factory getFactory() const override
SkScalar begin(SkScalar contourLength) const override
static void RegisterFlattenables()
static sk_sp< SkPathEffect > Make(const SkPath &path, SkScalar advance, SkScalar phase, Style)
bool getMatrix(SkScalar distance, SkMatrix *matrix, MatrixFlags flags=kGetPosAndTan_MatrixFlag)
SkScalar getLength()
bool getPosTan(SkScalar distance, SkPoint *position, SkVector *tangent)
Verb next(SkPoint pts[4])
Definition: SkPath.cpp:1901
SkScalar conicWeight() const
Definition: SkPath.h:1535
Definition: SkPath.h:59
uint32_t getGenerationID() const
Definition: SkPath.cpp:366
void updateBoundsCache() const
Definition: SkPath.h:524
@ kClose_Verb
Definition: SkPath.h:1471
@ kMove_Verb
Definition: SkPath.h:1466
@ kConic_Verb
Definition: SkPath.h:1469
@ kDone_Verb
Definition: SkPath.h:1472
@ kCubic_Verb
Definition: SkPath.h:1470
@ kQuad_Verb
Definition: SkPath.h:1468
@ kLine_Verb
Definition: SkPath.h:1467
void setFillStyle()
Definition: SkStrokeRec.cpp:81
float SkScalar
Definition: extension.cpp:12
size_t length
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
dst
Definition: cp.py:12
float fX
x-axis value
Definition: SkPoint_impl.h:164
void set(float x, float y)
Definition: SkPoint_impl.h:200
float fY
y-axis value
Definition: SkPoint_impl.h:165