mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
sw_engine/stroke: enhanced the quality of the dash line corners.
Previously, the engine didn't properly cover the dash line corner styles because it considered a new line to start at the corner. This update modifies the logic to recognize curved lines as a single line, including the corners. There may still be some quality issues, but it's an improvement over the previous version. @Issue: https://github.com/thorvg/thorvg/issues/121
This commit is contained in:
parent
12260198d1
commit
3d06d5552f
3 changed files with 43 additions and 17 deletions
|
@ -205,6 +205,7 @@ struct SwDashStroke
|
||||||
float* pattern = nullptr;
|
float* pattern = nullptr;
|
||||||
uint32_t cnt = 0;
|
uint32_t cnt = 0;
|
||||||
bool curOpGap = false;
|
bool curOpGap = false;
|
||||||
|
bool move = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwShape
|
struct SwShape
|
||||||
|
|
|
@ -121,7 +121,10 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
|
||||||
if (len < dash.curLen) {
|
if (len < dash.curLen) {
|
||||||
dash.curLen -= len;
|
dash.curLen -= len;
|
||||||
if (!dash.curOpGap) {
|
if (!dash.curOpGap) {
|
||||||
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
if (dash.move) {
|
||||||
|
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
||||||
|
dash.move = false;
|
||||||
|
}
|
||||||
_outlineLineTo(*dash.outline, to, transform);
|
_outlineLineTo(*dash.outline, to, transform);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -131,7 +134,10 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
|
||||||
len -= dash.curLen;
|
len -= dash.curLen;
|
||||||
_lineSplitAt(cur, dash.curLen, left, right);
|
_lineSplitAt(cur, dash.curLen, left, right);
|
||||||
if (!dash.curOpGap) {
|
if (!dash.curOpGap) {
|
||||||
_outlineMoveTo(*dash.outline, &left.pt1, transform);
|
if (dash.move || dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) {
|
||||||
|
_outlineMoveTo(*dash.outline, &left.pt1, transform);
|
||||||
|
dash.move = false;
|
||||||
|
}
|
||||||
_outlineLineTo(*dash.outline, &left.pt2, transform);
|
_outlineLineTo(*dash.outline, &left.pt2, transform);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,11 +148,15 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
|
||||||
dash.curOpGap = !dash.curOpGap;
|
dash.curOpGap = !dash.curOpGap;
|
||||||
cur = right;
|
cur = right;
|
||||||
dash.ptCur = cur.pt1;
|
dash.ptCur = cur.pt1;
|
||||||
|
dash.move = true;
|
||||||
}
|
}
|
||||||
//leftovers
|
//leftovers
|
||||||
dash.curLen -= len;
|
dash.curLen -= len;
|
||||||
if (!dash.curOpGap) {
|
if (!dash.curOpGap) {
|
||||||
_outlineMoveTo(*dash.outline, &cur.pt1, transform);
|
if (dash.move) {
|
||||||
|
_outlineMoveTo(*dash.outline, &cur.pt1, transform);
|
||||||
|
dash.move = false;
|
||||||
|
}
|
||||||
_outlineLineTo(*dash.outline, &cur.pt2, transform);
|
_outlineLineTo(*dash.outline, &cur.pt2, transform);
|
||||||
}
|
}
|
||||||
if (dash.curLen < 1 && TO_SWCOORD(len) > 1) {
|
if (dash.curLen < 1 && TO_SWCOORD(len) > 1) {
|
||||||
|
@ -168,21 +178,22 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
||||||
if (len < dash.curLen) {
|
if (len < dash.curLen) {
|
||||||
dash.curLen -= len;
|
dash.curLen -= len;
|
||||||
if (!dash.curOpGap) {
|
if (!dash.curOpGap) {
|
||||||
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
if (dash.move) {
|
||||||
|
_outlineMoveTo(*dash.outline, &dash.ptCur, transform);
|
||||||
|
dash.move = false;
|
||||||
|
}
|
||||||
_outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform);
|
_outlineCubicTo(*dash.outline, ctrl1, ctrl2, to, transform);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool begin = true; //starting with move_to
|
|
||||||
while (len > dash.curLen) {
|
while (len > dash.curLen) {
|
||||||
Bezier left, right;
|
Bezier left, right;
|
||||||
if (dash.curLen > 0) {
|
if (dash.curLen > 0) {
|
||||||
len -= dash.curLen;
|
len -= dash.curLen;
|
||||||
bezSplitAt(cur, dash.curLen, left, right);
|
bezSplitAt(cur, dash.curLen, left, right);
|
||||||
if (!dash.curOpGap) {
|
if (!dash.curOpGap) {
|
||||||
// leftovers from a previous command don't require moveTo
|
if (dash.move || dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) {
|
||||||
if (begin || dash.pattern[dash.curIdx] - dash.curLen < FLT_EPSILON) {
|
|
||||||
_outlineMoveTo(*dash.outline, &left.start, transform);
|
_outlineMoveTo(*dash.outline, &left.start, transform);
|
||||||
begin = false;
|
dash.move = false;
|
||||||
}
|
}
|
||||||
_outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end, transform);
|
_outlineCubicTo(*dash.outline, &left.ctrl1, &left.ctrl2, &left.end, transform);
|
||||||
}
|
}
|
||||||
|
@ -194,11 +205,15 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
||||||
dash.curOpGap = !dash.curOpGap;
|
dash.curOpGap = !dash.curOpGap;
|
||||||
cur = right;
|
cur = right;
|
||||||
dash.ptCur = right.start;
|
dash.ptCur = right.start;
|
||||||
|
dash.move = true;
|
||||||
}
|
}
|
||||||
//leftovers
|
//leftovers
|
||||||
dash.curLen -= len;
|
dash.curLen -= len;
|
||||||
if (!dash.curOpGap) {
|
if (!dash.curOpGap) {
|
||||||
_outlineMoveTo(*dash.outline, &cur.start, transform);
|
if (dash.move) {
|
||||||
|
_outlineMoveTo(*dash.outline, &cur.start, transform);
|
||||||
|
dash.move = false;
|
||||||
|
}
|
||||||
_outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end, transform);
|
_outlineCubicTo(*dash.outline, &cur.ctrl1, &cur.ctrl2, &cur.end, transform);
|
||||||
}
|
}
|
||||||
if (dash.curLen < 1 && TO_SWCOORD(len) > 1) {
|
if (dash.curLen < 1 && TO_SWCOORD(len) > 1) {
|
||||||
|
@ -212,6 +227,22 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _dashClose(SwDashStroke& dash, const Matrix* transform)
|
||||||
|
{
|
||||||
|
_dashLineTo(dash, &dash.ptStart, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const Point* pts, const Matrix* transform)
|
||||||
|
{
|
||||||
|
dash.curIdx = offIdx % dash.cnt;
|
||||||
|
dash.curLen = dash.pattern[dash.curIdx] - offset;
|
||||||
|
dash.curOpGap = offIdx % 2;
|
||||||
|
dash.ptStart = dash.ptCur = *pts;
|
||||||
|
dash.move = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, float length, SwMpool* mpool, unsigned tid)
|
static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, float length, SwMpool* mpool, unsigned tid)
|
||||||
{
|
{
|
||||||
const PathCommand* cmds = rshape->path.cmds.data;
|
const PathCommand* cmds = rshape->path.cmds.data;
|
||||||
|
@ -261,7 +292,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
||||||
trimmed = true;
|
trimmed = true;
|
||||||
//just a dasy style.
|
//just a dasy style.
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (dash.cnt == 0) return nullptr;
|
if (dash.cnt == 0) return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,15 +333,11 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
|
||||||
while (cmdCnt-- > 0) {
|
while (cmdCnt-- > 0) {
|
||||||
switch (*cmds) {
|
switch (*cmds) {
|
||||||
case PathCommand::Close: {
|
case PathCommand::Close: {
|
||||||
_dashLineTo(dash, &dash.ptStart, transform);
|
_dashClose(dash, transform);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PathCommand::MoveTo: {
|
case PathCommand::MoveTo: {
|
||||||
//reset the dash
|
_dashMoveTo(dash, offIdx, offset, pts, transform);
|
||||||
dash.curIdx = offIdx % dash.cnt;
|
|
||||||
dash.curLen = dash.pattern[dash.curIdx] - offset;
|
|
||||||
dash.curOpGap = offIdx % 2;
|
|
||||||
dash.ptStart = dash.ptCur = *pts;
|
|
||||||
++pts;
|
++pts;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -689,7 +689,6 @@ static void _endSubPath(SwStroke& stroke)
|
||||||
|
|
||||||
//No specific corner processing is required if the turn is 0
|
//No specific corner processing is required if the turn is 0
|
||||||
if (turn != 0) {
|
if (turn != 0) {
|
||||||
|
|
||||||
//when we turn to the right, the inside is 0
|
//when we turn to the right, the inside is 0
|
||||||
int32_t inside = 0;
|
int32_t inside = 0;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue