26 if (!
p.setLength(
len)) {
27 SkDebugf(
"Failed to set point length\n");
40 return SkPath::Make(fPoints.data(), fPoints.size(), fVerbs.data(), fVerbs.size(),
nullptr,
61 int countPoints()
const {
return fPoints.size(); }
63 int countVerbs()
const {
return fVerbs.size(); }
65 bool getLastPt(
SkPoint* lastPt)
const {
66 if (fPoints.empty()) {
69 *lastPt = fPoints.back();
73 void setLastPt(
SkPoint lastPt) {
74 if (fPoints.empty()) {
77 fPoints.back().set(lastPt.
fX, lastPt.
fY);
81 const std::vector<uint8_t>& verbs()
const {
return fVerbs; }
83 const std::vector<SkPoint>&
points()
const {
return fPoints; }
86 std::vector<uint8_t> fVerbs;
87 std::vector<SkPoint> fPoints;
104 PathRecorder fInner, fOuter;
113 enum class CapLocation { Start, End };
114 void endcap(CapLocation loc);
120 static void appendPathReversed(
const PathRecorder&
path, PathRecorder*
result);
126 static float squaredLineLength(
const PathSegment& lineSeg);
130 fRadius =
paint.getStrokeWidth() / 2;
131 fCap =
paint.getStrokeCap();
144 bool firstSegment =
true;
148 join(prevSegment, segment);
152 switch (segment.fVerb) {
154 strokeLine(segment, firstSegment);
160 SkDebugf(
"Unhandled path verb %d\n", segment.fVerb);
165 firstSegment =
false;
169 const bool isClosed =
path.isLastContourClosed();
171 SkDebugf(
"Unhandled closed contour\n");
173 endcap(CapLocation::End);
177 appendPathReversed(fInner, &fOuter);
178 endcap(CapLocation::Start);
180 return fOuter.getPath();
183void SkPathStroker2::strokeLine(
const PathSegment&
line,
bool needsMove) {
195void SkPathStroker2::endcap(CapLocation loc) {
196 const auto buttCap = [
this](CapLocation loc) {
197 if (loc == CapLocation::Start) {
203 fInner.getLastPt(&innerLastPt);
204 fOuter.lineTo(innerLastPt);
213 SkDebugf(
"Unhandled endcap %d\n", fCap);
222 const SkPoint miterMidpt = curr.fPoints[0];
225 SkPoint after = unitNormal(curr, 0);
228 PathRecorder *outer = &fOuter, *inner = &fInner;
229 if (!isClockwise(before, after)) {
231 before = rotate180(before);
232 after = rotate180(after);
235 const float cosTheta = before.
dot(after);
243 SkPoint miterVec = before + after;
251 const float sinHalfTheta = sqrtf(0.5 * (1 + cosTheta));
252 const float halfMiterLength = fRadius / sinHalfTheta;
257 outer->lineTo(miterMidpt + miterVec);
258 outer->lineTo(miterMidpt +
dest);
263 const SkPoint prevUnitTangent = rotate90(before);
264 const float radiusSquared = fRadius * fRadius;
266 const float cosAlpha = prevUnitTangent.
dot(-after);
272 const float threshold1 = radiusSquared * cosAlpha * cosAlpha;
277 const float threshold2 = halfMiterLength * halfMiterLength - radiusSquared;
280 const float maxLenSqd =
std::max(threshold1, threshold2);
281 const bool needsInnerLoop =
282 squaredLineLength(
prev) < maxLenSqd || squaredLineLength(curr) < maxLenSqd;
283 if (needsInnerLoop) {
288 inner->lineTo(miterMidpt);
289 inner->lineTo(miterMidpt -
dest);
292 inner->setLastPt(miterMidpt - miterVec);
298 miterJoin(
prev, curr);
302 miterJoin(
prev, curr);
307void SkPathStroker2::appendPathReversed(
const PathRecorder&
path, PathRecorder*
result) {
308 const int numVerbs =
path.countVerbs();
309 const int numPoints =
path.countPoints();
310 const std::vector<uint8_t>& verbs =
path.verbs();
311 const std::vector<SkPoint>&
points =
path.points();
313 for (
int i = numVerbs - 1, j = numPoints;
i >= 0;
i--) {
334 SkDebugf(
"Unhandled verb for unit normal %d\n", seg.fVerb);
338 const SkPoint tangent = seg.fPoints[1] - seg.fPoints[0];
343float SkPathStroker2::squaredLineLength(
const PathSegment& lineSeg) {
345 const SkPoint diff = lineSeg.fPoints[1] - lineSeg.fPoints[0];
346 return diff.
dot(diff);
354 bool fShowSkiaStroke, fShowHidden, fShowSkeleton;
356 SkPaint fPtsPaint, fStrokePaint, fMirrorStrokePaint, fNewFillPaint, fHiddenPaint,
358 inline static constexpr int kN = 3;
364 fPts[0] = {500, 200};
365 fPts[1] = {300, 200};
366 fPts[2] = {100, 100};
378 fMirrorStrokePaint.
setColor(0x80FFFF00);
390 fName =
"SimpleStroker";
396 this->toggle(fShowSkeleton);
399 this->toggle(fShowSkiaStroke);
402 this->toggle(fShowHidden);
420 this->makePath(&
path);
425 if (fShowSkiaStroke) {
430 SkPathStroker2 stroker;
431 SkPath fillPath = stroker.getFillPath(
path, fStrokePaint);
432 canvas->
drawPath(fillPath, fNewFillPaint);
435 canvas->
drawPath(fillPath, fHiddenPaint);
449 canvas->
drawPath(hidden, fHiddenPaint);
460 for (
int i = 0;
i < kN; ++
i) {
478 for (
int i = 1;
i < kN; ++
i) {
static bool rewind(EdgeList *activeEdges, Vertex **current, Vertex *dst, const Comparator &c)
static const int points[]
static float prev(float f)
constexpr SkColor SK_ColorRED
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
void swap(sk_sp< T > &a, sk_sp< T > &b)
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
#define setLength(p, len)
bool onChar(SkUnichar uni) override
void draw(SkCanvas *canvas) override
Click * onFindClickHandler(SkScalar x, SkScalar y, skui::ModifierKey modi) override
bool onClick(ClickHandlerSlide::Click *) override
void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint &paint)
void translate(SkScalar dx, SkScalar dy)
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
void drawPath(const SkPath &path, const SkPaint &paint)
@ kPoints_PointMode
draw each point separately
@ kButt_Cap
no stroke extension
void setStyle(Style style)
void setColor(SkColor color)
void setAntiAlias(bool aa)
void setStrokeCap(Cap cap)
@ kStroke_Style
set to stroke geometry
@ kMiter_Join
extends to miter limit
void setStrokeWidth(SkScalar width)
static SkPath Make(const SkPoint[], int pointCount, const uint8_t[], int verbCount, const SkScalar[], int conicWeightCount, SkPathFillType, bool isVolatile=false)
static float max(float r, float g, float b)
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
SK_API bool FillPathWithPaint(const SkPath &src, const SkPaint &paint, SkPath *dst, const SkRect *cullRect, SkScalar resScale=1)
static SkString join(const CommandLineFlags::StringArray &)
bool setLength(float length)
float dot(const SkVector &vec) const
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
bool intersects(const SkRect &r) const