From 2c73da0e20b159a01a0ec56534aad563b467e436 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 161e3e13..b0b801b3 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.cpp +++ b/src/renderer/gl_engine/tvgGlTessellator.cpp @@ -1960,6 +1960,7 @@ DashStroke::DashStroke(Array *cmds, Array *pts, uint32_t das mCurrLen(), mCurrIdx(), mCurOpGap(false), + mMove(true), mPtStart(), mPtCur() { @@ -1999,6 +2000,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; @@ -2024,23 +2026,31 @@ void DashStroke::dashLineTo(const Point& to) { auto len = length(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 { Line curr = {mPtCur, to}; - while (len > mCurrLen) { + while (len - mCurrLen > 0.0001f) { Line right; if (mCurrLen > 0.0f) { Line left; curr.split(mCurrLen, left, right); len -= mCurrLen; if (!mCurOpGap) { - this->moveTo(left.pt1); + if (mMove || mDashPattern[mCurrIdx] - mCurrLen < FLOAT_EPSILON) { + this->moveTo(left.pt1); + mMove = false; + } this->lineTo(left.pt2); } } else right = curr; @@ -2049,10 +2059,14 @@ void DashStroke::dashLineTo(const Point& to) mCurOpGap = !mCurOpGap; curr = right; mPtCur = curr.pt1; + mMove = true; } mCurrLen -= len; if (!mCurOpGap) { - this->moveTo(curr.pt1); + if (mMove) { + this->moveTo(curr.pt1); + mMove = false; + } this->lineTo(curr.pt2); } @@ -2077,21 +2091,29 @@ void DashStroke::dashCubicTo(const Point& cnt1, const Point& cnt2, const Point& 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; @@ -2100,11 +2122,15 @@ void DashStroke::dashCubicTo(const Point& cnt1, const Point& cnt2, const Point& 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 522e2b87..2feaa38a 100644 --- a/src/renderer/gl_engine/tvgGlTessellator.h +++ b/src/renderer/gl_engine/tvgGlTessellator.h @@ -139,6 +139,7 @@ private: float mCurrLen; int32_t mCurrIdx; bool mCurOpGap; + bool mMove; Point mPtStart; Point mPtCur; };