sw_engine: move trimming logic to TrimPath

The trim handling from sw_engine has been removed.
Instead the common logic from the TrimPath structure
is used.
On the sw_engine side, the dashed outline is now
used for both: dashed and/or trimmed strokes.

@Issue: https://github.com/thorvg/thorvg/issues/2854
This commit is contained in:
Mira Grudzinska 2025-01-14 22:54:41 +01:00 committed by Hermet Park
parent 669d6dc580
commit 8ed4c2f302
2 changed files with 64 additions and 128 deletions

View file

@ -288,7 +288,7 @@ struct SwMpool
{ {
SwOutline* outline; SwOutline* outline;
SwOutline* strokeOutline; SwOutline* strokeOutline;
SwOutline* dashOutline; SwOutline* dashOutline; //Trimming treated as a special case of dashing
unsigned allocSize; unsigned allocSize;
}; };

View file

@ -226,14 +226,6 @@ static void _dashClose(SwDashStroke& dash, const Matrix& transform)
} }
static void _dashMoveTo(SwDashStroke& dash, const Point* pts)
{
dash.ptCur = *pts;
dash.ptStart = *pts;
dash.move = true;
}
static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const Point* pts) static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const Point* pts)
{ {
dash.curIdx = offIdx % dash.cnt; dash.curIdx = offIdx % dash.cnt;
@ -244,112 +236,36 @@ static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const
} }
static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length, float trimBegin, float trimEnd) static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& transform, SwMpool* mpool, unsigned tid, bool trimmed)
{ {
auto begin = length * trimBegin; PathCommand *cmds, *trimmedCmds = nullptr;
auto end = length * trimEnd; Point *pts, *trimmedPts = nullptr;
uint32_t cmdCnt, ptsCnt;
//default if (trimmed) {
if (end > begin) { RenderPath trimmedPath;
if (begin > 0.0f) dash->cnt = 4; if (!rshape->stroke->trim.trim(rshape->path, trimmedPath)) return nullptr;
else dash->cnt = 2;
//looping
} else dash->cnt = 3;
if (dash->cnt == 2) { cmds = trimmedCmds = trimmedPath.cmds.data;
dash->pattern[0] = end - begin; cmdCnt = trimmedPath.cmds.count;
dash->pattern[1] = length - (end - begin); pts = trimmedPts = trimmedPath.pts.data;
} else if (dash->cnt == 3) { ptsCnt = trimmedPath.pts.count;
dash->pattern[0] = end;
dash->pattern[1] = (begin - end); trimmedPath.cmds.data = nullptr;
dash->pattern[2] = length - begin; trimmedPath.pts.data = nullptr;
} else { } else {
dash->pattern[0] = 0; //zero dash to start with a space. cmds = rshape->path.cmds.data;
dash->pattern[1] = begin; cmdCnt = rshape->path.cmds.count;
dash->pattern[2] = end - begin; pts = rshape->path.pts.data;
dash->pattern[3] = length - end; ptsCnt = rshape->path.pts.count;
} }
}
static float _outlineLength(const RenderShape* rshape, uint32_t shiftPts, uint32_t shiftCmds, bool subpath)
{
const PathCommand* cmds = rshape->path.cmds.data + shiftCmds;
auto cmdCnt = rshape->path.cmds.count - shiftCmds;
const Point* pts = rshape->path.pts.data + shiftPts;
auto ptsCnt = rshape->path.pts.count - shiftPts;
//No actual shape data
if (cmdCnt <= 0 || ptsCnt <= 0) return 0.0f;
const Point* close = nullptr;
auto len = 0.0f;
//must begin with moveTo
if (cmds[0] == PathCommand::MoveTo) {
close = pts;
cmds++;
pts++;
cmdCnt--;
}
while (cmdCnt-- > 0) {
switch (*cmds) {
case PathCommand::Close: {
len += length(pts - 1, close);
if (subpath) return len;
break;
}
case PathCommand::MoveTo: {
if (subpath) return len;
close = pts;
++pts;
break;
}
case PathCommand::LineTo: {
len += length(pts - 1, pts);
++pts;
break;
}
case PathCommand::CubicTo: {
len += Bezier{*(pts - 1), *pts, *(pts + 1), *(pts + 2)}.length();
pts += 3;
break;
}
}
++cmds;
}
return len;
}
static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& transform, bool trimmed, SwMpool* mpool, unsigned tid)
{
const PathCommand* cmds = rshape->path.cmds.data;
auto cmdCnt = rshape->path.cmds.count;
const Point* pts = rshape->path.pts.data;
auto ptsCnt = rshape->path.pts.count;
//No actual shape data //No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return nullptr; if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
auto startPts = pts;
auto startCmds = cmds;
SwDashStroke dash; SwDashStroke dash;
auto offset = 0.0f; auto offset = 0.0f;
dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset); dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
auto simultaneous = rshape->stroke->trim.simultaneous;
float trimBegin = 0.0f, trimEnd = 1.0f;
if (trimmed) rshape->stroke->trim.get(trimBegin, trimEnd);
if (dash.cnt == 0) {
if (trimmed) dash.pattern = (float*)malloc(sizeof(float) * 4);
else return nullptr;
} else {
//TODO: handle dash + trim - for now trimming ignoring is forced
trimmed = false;
}
//offset //offset
auto patternLength = 0.0f; auto patternLength = 0.0f;
@ -373,7 +289,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans
//must begin with moveTo //must begin with moveTo
if (cmds[0] == PathCommand::MoveTo) { if (cmds[0] == PathCommand::MoveTo) {
if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous), trimBegin, trimEnd);
_dashMoveTo(dash, offIdx, offset, pts); _dashMoveTo(dash, offIdx, offset, pts);
cmds++; cmds++;
pts++; pts++;
@ -386,12 +301,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans
break; break;
} }
case PathCommand::MoveTo: { case PathCommand::MoveTo: {
if (trimmed) { _dashMoveTo(dash, offIdx, offset, pts);
if (simultaneous) {
_trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true), trimBegin, trimEnd);
_dashMoveTo(dash, offIdx, offset, pts);
} else _dashMoveTo(dash, pts);
} else _dashMoveTo(dash, offIdx, offset, pts);
++pts; ++pts;
break; break;
} }
@ -409,9 +319,10 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix& trans
++cmds; ++cmds;
} }
_outlineEnd(*dash.outline); free(trimmedCmds);
free(trimmedPts);
if (trimmed) free(dash.pattern); _outlineEnd(*dash.outline);
return dash.outline; return dash.outline;
} }
@ -437,18 +348,34 @@ static bool _axisAlignedRect(const SwOutline* outline)
} }
static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix& transform, SwMpool* mpool, unsigned tid, bool hasComposite) static SwOutline* _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix& transform, SwMpool* mpool, unsigned tid, bool hasComposite, bool trimmed = false)
{ {
const PathCommand* cmds = rshape->path.cmds.data; PathCommand *cmds, *trimmedCmds = nullptr;
auto cmdCnt = rshape->path.cmds.count; Point *pts, *trimmedPts = nullptr;
const Point* pts = rshape->path.pts.data; uint32_t cmdCnt, ptsCnt;
auto ptsCnt = rshape->path.pts.count;
if (trimmed) {
RenderPath trimmedPath;
if (!rshape->stroke->trim.trim(rshape->path, trimmedPath)) return nullptr;
cmds = trimmedCmds = trimmedPath.cmds.data;
cmdCnt = trimmedPath.cmds.count;
pts = trimmedPts = trimmedPath.pts.data;
ptsCnt = trimmedPath.pts.count;
trimmedPath.cmds.data = nullptr;
trimmedPath.pts.data = nullptr;
} else {
cmds = rshape->path.cmds.data;
cmdCnt = rshape->path.cmds.count;
pts = rshape->path.pts.data;
ptsCnt = rshape->path.pts.count;
}
//No actual shape data //No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return false; if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
shape->outline = mpoolReqOutline(mpool, tid); auto outline = trimmed ? mpoolReqDashOutline(mpool, tid) : mpoolReqOutline(mpool, tid);
auto outline = shape->outline;
auto closed = false; auto closed = false;
//Generate Outlines //Generate Outlines
@ -482,10 +409,12 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix&
if (!closed) _outlineEnd(*outline); if (!closed) _outlineEnd(*outline);
outline->fillRule = rshape->rule; outline->fillRule = rshape->rule;
shape->outline = outline;
shape->fastTrack = (!hasComposite && _axisAlignedRect(shape->outline)); free(trimmedCmds);
return true; free(trimmedPts);
if (!trimmed) shape->fastTrack = (!hasComposite && _axisAlignedRect(outline));
return outline;
} }
@ -495,7 +424,8 @@ static bool _genOutline(SwShape* shape, const RenderShape* rshape, const Matrix&
bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite) bool shapePrepare(SwShape* shape, const RenderShape* rshape, const Matrix& transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid, bool hasComposite)
{ {
if (!_genOutline(shape, rshape, transform, mpool, tid, hasComposite)) return false; if (auto out = _genOutline(shape, rshape, transform, mpool, tid, hasComposite)) shape->outline = out;
else return false;
if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false; if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion, shape->fastTrack)) return false;
shape->bbox = renderRegion; shape->bbox = renderRegion;
@ -581,16 +511,22 @@ bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix&
auto dashStroking = false; auto dashStroking = false;
auto ret = true; auto ret = true;
//Dash style (+trimming) //Dash style with/without trimming
auto trimmed = rshape->strokeTrim(); auto trimmed = rshape->strokeTrim();
if (rshape->stroke->dashCnt > 0 || trimmed) { if (rshape->stroke->dashCnt > 0) {
shapeOutline = _genDashOutline(rshape, transform, trimmed, mpool, tid); shapeOutline = _genDashOutline(rshape, transform, mpool, tid, trimmed);
if (!shapeOutline) return false;
dashStroking = true;
//Trimming
} else if (trimmed) {
shapeOutline = _genOutline(shape, rshape, transform, mpool, tid, false, true);
if (!shapeOutline) return false; if (!shapeOutline) return false;
dashStroking = true; dashStroking = true;
//Normal style //Normal style
} else { } else {
if (!shape->outline) { if (!shape->outline) {
if (!_genOutline(shape, rshape, transform, mpool, tid, false)) return false; if (auto out = _genOutline(shape, rshape, transform, mpool, tid, false)) shape->outline = out;
else return false;
} }
shapeOutline = shape->outline; shapeOutline = shape->outline;
} }