From 5114a87e3dae147604795214ed04bd5165fac7f2 Mon Sep 17 00:00:00 2001 From: Mira Grudzinska Date: Tue, 25 Feb 2025 00:16:02 +0100 Subject: [PATCH] gl_engine: fix line join while dashing While dashing, changing the path command each time caused a new 'move to' command to be added, even when dash segments across different path commands should have been connected. @Issue: https://github.com/thorvg/thorvg/issues/3231 --- src/renderer/gl_engine/tvgGlTessellator.cpp | 46 ++++++++++++++++----- src/renderer/gl_engine/tvgGlTessellator.h | 1 + 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/renderer/gl_engine/tvgGlTessellator.cpp b/src/renderer/gl_engine/tvgGlTessellator.cpp index 73664964..8846918a 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.cpp +++ b/src/renderer/gl_engine/tvgGlTessellator.cpp @@ -2200,6 +2200,7 @@ DashStroke::DashStroke(Array *cmds, Array *pts, uint32_t das mCurrLen(), mCurrIdx(), mCurOpGap(false), + mMove(true), mPtStart(), mPtCur() { @@ -2240,6 +2241,7 @@ void DashStroke::doStroke(const PathCommand *cmds, uint32_t cmd_count, const Poi mCurrIdx = idx; mCurrLen = mDashPattern[idx] - offset; mCurOpGap = gap; + mMove = true; mPtStart = mPtCur = *pts; pts++; break; @@ -2267,24 +2269,32 @@ void DashStroke::dashLineTo(const GlPoint &to) { float len = detail::_pointLength(mPtCur - to); - if (len < mCurrLen) { + if (tvg::zero(len)) { + this->moveTo(mPtCur); + } else if (len <= mCurrLen) { mCurrLen -= len; if (!mCurOpGap) { - this->moveTo(mPtCur); + if (mMove) { + this->moveTo(mPtCur); + mMove = false; + } this->lineTo(to); } } else { detail::Line curr{mPtCur, to}; - while (len > mCurrLen) { + while (len - mCurrLen > 0.0001f) { detail::Line right; if (mCurrLen > 0.0f) { detail::Line left; detail::_lineSplitAt(curr, mCurrLen, &left, &right); len -= mCurrLen; if (!mCurOpGap) { - this->moveTo(left.p1); + if (mMove || mDashPattern[mCurrIdx] - mCurrLen < FLOAT_EPSILON) { + this->moveTo(left.p1); + mMove = false; + } this->lineTo(left.p2); } } else right = curr; @@ -2293,10 +2303,14 @@ void DashStroke::dashLineTo(const GlPoint &to) mCurOpGap = !mCurOpGap; curr = right; mPtCur = curr.p1; + mMove = true; } mCurrLen -= len; if (!mCurOpGap) { - this->moveTo(curr.p1); + if (mMove) { + this->moveTo(curr.p1); + mMove = false; + } this->lineTo(curr.p2); } @@ -2321,21 +2335,29 @@ void DashStroke::dashCubicTo(const GlPoint &cnt1, const GlPoint &cnt2, const GlP auto len = cur.length(); - if (len < mCurrLen) { + if (tvg::zero(len)) { + this->moveTo(mPtCur); + } else if (len <= mCurrLen) { mCurrLen -= len; if (!mCurOpGap) { - this->moveTo(mPtCur); + if (mMove) { + this->moveTo(mPtCur); + mMove = false; + } this->cubicTo(cnt1, cnt2, end); } } else { - while (len > mCurrLen) { + while (len - mCurrLen > 0.0001f) { Bezier right; if (mCurrLen > 0.0f) { Bezier left; cur.split(mCurrLen, left, right); len -= mCurrLen; if (!mCurOpGap) { - this->moveTo(left.start); + if (mMove || mDashPattern[mCurrIdx] - mCurrLen < FLOAT_EPSILON) { + this->moveTo(left.start); + mMove = false; + } this->cubicTo(left.ctrl1, left.ctrl2, left.end); } } else right = cur; @@ -2344,11 +2366,15 @@ void DashStroke::dashCubicTo(const GlPoint &cnt1, const GlPoint &cnt2, const GlP mCurOpGap = !mCurOpGap; cur = right; mPtCur = cur.start; + mMove = true; } mCurrLen -= len; if (!mCurOpGap) { - this->moveTo(cur.start); + if (mMove) { + this->moveTo(cur.start); + mMove = false; + } this->cubicTo(cur.ctrl1, cur.ctrl2, cur.end); } diff --git a/src/renderer/gl_engine/tvgGlTessellator.h b/src/renderer/gl_engine/tvgGlTessellator.h index 00a15b2b..20f2d573 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.h +++ b/src/renderer/gl_engine/tvgGlTessellator.h @@ -187,6 +187,7 @@ private: float mCurrLen; int32_t mCurrIdx; bool mCurOpGap; + bool mMove; GlPoint mPtStart; GlPoint mPtCur; };