sw_engine: rectify consecutive line drawings.

There are differences in behavior compared to the SVG spec,
especially when consecutive line drawings occur without a moveTo command
following a closePath command.

Actually, thorvg didn't care the behavior in that scenario,
this update ensures the scenario is handled correctly
to align with the SVG specification.

issue: https://github.com/thorvg/thorvg/issues/1487
This commit is contained in:
Hermet Park 2024-03-26 23:48:54 +09:00 committed by Hermet Park
parent 06cc9709e6
commit 1f996c1382
2 changed files with 25 additions and 6 deletions

View file

@ -0,0 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2h12v12H2zl12 12" fill="none" stroke-width="2" stroke="#ffca5f"/></svg>

After

Width:  |  Height:  |  Size: 166 B

View file

@ -28,6 +28,19 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
static bool _outlineJump(SwOutline& outline)
{
//Make a contour if lineTo/curveTo without calling close/moveTo beforehand.
if (!outline.pts.empty()) {
outline.cntrs.push(outline.pts.count - 1);
outline.pts.push(outline.pts[outline.cntrs.last()]);
outline.types.push(SW_CURVE_TYPE_POINT);
}
return false;
}
static void _outlineEnd(SwOutline& outline) static void _outlineEnd(SwOutline& outline)
{ {
if (outline.pts.empty()) return; if (outline.pts.empty()) return;
@ -68,20 +81,22 @@ static void _outlineCubicTo(SwOutline& outline, const Point* ctrl1, const Point*
} }
static void _outlineClose(SwOutline& outline) static bool _outlineClose(SwOutline& outline)
{ {
uint32_t i = 0; uint32_t i;
if (outline.cntrs.count > 0) i = outline.cntrs.last() + 1; if (outline.cntrs.count > 0) i = outline.cntrs.last() + 1;
else i = 0; //First Path else i = 0;
//Make sure there is at least one point in the current path //Make sure there is at least one point in the current path
if (outline.pts.count == i) return; if (outline.pts.count == i) return false;
//Close the path //Close the path
outline.pts.push(outline.pts[i]); outline.pts.push(outline.pts[i]);
outline.types.push(SW_CURVE_TYPE_POINT); outline.types.push(SW_CURVE_TYPE_POINT);
outline.closed.push(true); outline.closed.push(true);
return true;
} }
@ -398,25 +413,28 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix*
shape->outline = mpoolReqOutline(mpool, tid); shape->outline = mpoolReqOutline(mpool, tid);
auto outline = shape->outline; auto outline = shape->outline;
bool closed = false;
//Generate Outlines //Generate Outlines
while (cmdCnt-- > 0) { while (cmdCnt-- > 0) {
switch (*cmds) { switch (*cmds) {
case PathCommand::Close: { case PathCommand::Close: {
_outlineClose(*outline); if (!closed) closed = _outlineClose(*outline);
break; break;
} }
case PathCommand::MoveTo: { case PathCommand::MoveTo: {
if (closed) closed = false;
_outlineMoveTo(*outline, pts, transform); _outlineMoveTo(*outline, pts, transform);
++pts; ++pts;
break; break;
} }
case PathCommand::LineTo: { case PathCommand::LineTo: {
if (closed) closed = _outlineJump(*outline);
_outlineLineTo(*outline, pts, transform); _outlineLineTo(*outline, pts, transform);
++pts; ++pts;
break; break;
} }
case PathCommand::CubicTo: { case PathCommand::CubicTo: {
if (closed) closed = _outlineJump(*outline);
_outlineCubicTo(*outline, pts, pts + 1, pts + 2, transform); _outlineCubicTo(*outline, pts, pts + 1, pts + 2, transform);
pts += 3; pts += 3;
break; break;