mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
sw_engine: allow sharing shapes & connected strokes all in one.
This patch enhanced the sw raster engine to allow the both closed & open pathes in one shape rendering. @Issue: https://github.com/Samsung/thorvg/issues/266
This commit is contained in:
parent
669ac392ca
commit
e15b1dbc5f
5 changed files with 68 additions and 46 deletions
|
@ -105,8 +105,8 @@ struct SwOutline
|
|||
uint32_t ptsCnt; //number of points in the glyph
|
||||
uint32_t reservedPtsCnt;
|
||||
uint8_t* types; //curve type
|
||||
bool* closed; //opened or closed path?
|
||||
FillRule fillRule;
|
||||
bool opened; //opened path?
|
||||
};
|
||||
|
||||
struct SwSpan
|
||||
|
@ -190,7 +190,7 @@ struct SwStroke
|
|||
float sx, sy;
|
||||
|
||||
bool firstPt;
|
||||
bool openSubPath;
|
||||
bool closedSubPath;
|
||||
bool handleWideStrokes;
|
||||
};
|
||||
|
||||
|
|
|
@ -31,12 +31,18 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
|
|||
image->outline = mpoolReqOutline(mpool, tid);
|
||||
auto outline = image->outline;
|
||||
|
||||
outline->reservedPtsCnt = 5;
|
||||
outline->pts = static_cast<SwPoint*>(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint)));
|
||||
outline->types = static_cast<uint8_t*>(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t)));
|
||||
if (outline->reservedPtsCnt < 5) {
|
||||
outline->reservedPtsCnt = 5;
|
||||
outline->pts = static_cast<SwPoint*>(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint)));
|
||||
outline->types = static_cast<uint8_t*>(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t)));
|
||||
}
|
||||
|
||||
outline->reservedCntrsCnt = 1;
|
||||
outline->cntrs = static_cast<uint32_t*>(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t)));
|
||||
if (outline->reservedCntrsCnt < 1) {
|
||||
outline->reservedCntrsCnt = 1;
|
||||
outline->cntrs = static_cast<uint32_t*>(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t)));
|
||||
outline->closed = static_cast<bool*>(realloc(outline->closed, outline->reservedCntrsCnt * sizeof(bool)));
|
||||
outline->closed[0] = true;
|
||||
}
|
||||
|
||||
auto w = static_cast<float>(image->w);
|
||||
auto h = static_cast<float>(image->h);
|
||||
|
@ -55,8 +61,6 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
|
|||
outline->cntrs[outline->cntrsCnt] = outline->ptsCnt - 1;
|
||||
++outline->cntrsCnt;
|
||||
|
||||
outline->opened = false;
|
||||
|
||||
image->outline = outline;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -107,6 +107,9 @@ bool mpoolClear(SwMpool* mpool)
|
|||
free(p->types);
|
||||
p->types = nullptr;
|
||||
|
||||
free(p->closed);
|
||||
p->closed = nullptr;
|
||||
|
||||
p->cntrsCnt = p->reservedCntrsCnt = 0;
|
||||
p->ptsCnt = p->reservedPtsCnt = 0;
|
||||
|
||||
|
@ -122,6 +125,9 @@ bool mpoolClear(SwMpool* mpool)
|
|||
free(p->types);
|
||||
p->types = nullptr;
|
||||
|
||||
free(p->closed);
|
||||
p->closed = nullptr;
|
||||
|
||||
p->cntrsCnt = p->reservedCntrsCnt = 0;
|
||||
p->ptsCnt = p->reservedPtsCnt = 0;
|
||||
}
|
||||
|
|
|
@ -58,11 +58,20 @@ static void _lineSplitAt(const Line& cur, float at, Line& left, Line& right)
|
|||
}
|
||||
|
||||
|
||||
static void _growOutlineContour(SwOutline& outline, uint32_t n)
|
||||
static bool _growOutlineContour(SwOutline& outline, uint32_t n)
|
||||
{
|
||||
if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return;
|
||||
if (outline.reservedCntrsCnt >= outline.cntrsCnt + n) return false;
|
||||
outline.reservedCntrsCnt = outline.cntrsCnt + n;
|
||||
outline.cntrs = static_cast<uint32_t*>(realloc(outline.cntrs, outline.reservedCntrsCnt * sizeof(uint32_t)));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void _growOutlineClose(SwOutline& outline)
|
||||
{
|
||||
//Dash outlines are always opened.
|
||||
//Only normal outlines use this information, it sholud be same to their contour counts.
|
||||
outline.closed = static_cast<bool*>(realloc(outline.closed, outline.reservedCntrsCnt * sizeof(bool)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,6 +87,11 @@ static void _growOutlinePoint(SwOutline& outline, uint32_t n)
|
|||
static void _outlineEnd(SwOutline& outline)
|
||||
{
|
||||
_growOutlineContour(outline, 1);
|
||||
|
||||
if (outline.closed) {
|
||||
outline.closed[outline.cntrsCnt] = false;
|
||||
}
|
||||
|
||||
if (outline.ptsCnt > 0) {
|
||||
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
|
||||
++outline.cntrsCnt;
|
||||
|
@ -142,7 +156,7 @@ static void _outlineClose(SwOutline& outline)
|
|||
|
||||
//Make sure there is at least one point in the current path
|
||||
if (outline.ptsCnt == i) {
|
||||
outline.opened = true;
|
||||
outline.closed[outline.cntrsCnt] = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -153,7 +167,7 @@ static void _outlineClose(SwOutline& outline)
|
|||
outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
|
||||
++outline.ptsCnt;
|
||||
|
||||
outline.opened = false;
|
||||
outline.closed[outline.cntrsCnt] = true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -274,7 +288,6 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
|
|||
//OPTMIZE ME: Use mempool???
|
||||
dash.pattern = const_cast<float*>(pattern);
|
||||
dash.outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
|
||||
dash.outline->opened = true;
|
||||
|
||||
//smart reservation
|
||||
auto outlinePtsCnt = 0;
|
||||
|
@ -305,7 +318,7 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
|
|||
++outlinePtsCnt; //for close
|
||||
++outlineCntrsCnt; //for end
|
||||
|
||||
//Reserve Approximitely 20x...
|
||||
//No idea exact count.... Reserve Approximitely 20x...
|
||||
_growOutlinePoint(*dash.outline, outlinePtsCnt * 20);
|
||||
_growOutlineContour(*dash.outline, outlineCntrsCnt * 20);
|
||||
|
||||
|
@ -406,19 +419,18 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf
|
|||
|
||||
shape->outline = mpoolReqOutline(mpool, tid);
|
||||
auto outline = shape->outline;
|
||||
outline->opened = true;
|
||||
|
||||
_growOutlinePoint(*outline, outlinePtsCnt);
|
||||
_growOutlineContour(*outline, outlineCntrsCnt);
|
||||
|
||||
auto closed = false;
|
||||
if (_growOutlineContour(*outline, outlineCntrsCnt)) {
|
||||
_growOutlineClose(*outline);
|
||||
}
|
||||
|
||||
//Generate Outlines
|
||||
while (cmdCnt-- > 0) {
|
||||
switch(*cmds) {
|
||||
case PathCommand::Close: {
|
||||
_outlineClose(*outline);
|
||||
closed = true;
|
||||
break;
|
||||
}
|
||||
case PathCommand::MoveTo: {
|
||||
|
@ -442,8 +454,6 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf
|
|||
|
||||
_outlineEnd(*outline);
|
||||
|
||||
if (closed) outline->opened = false;
|
||||
|
||||
outline->fillRule = sdata->fillRule();
|
||||
shape->outline = outline;
|
||||
|
||||
|
@ -587,6 +597,7 @@ fail:
|
|||
if (shapeOutline->cntrs) free(shapeOutline->cntrs);
|
||||
if (shapeOutline->pts) free(shapeOutline->pts);
|
||||
if (shapeOutline->types) free(shapeOutline->types);
|
||||
if (shapeOutline->closed) free(shapeOutline->closed);
|
||||
free(shapeOutline);
|
||||
}
|
||||
mpoolRetStrokeOutline(mpool, tid);
|
||||
|
@ -640,4 +651,4 @@ void shapeDelStrokeFill(SwShape* shape)
|
|||
if (!shape->stroke->fill) return;
|
||||
fillFree(shape->stroke->fill);
|
||||
shape->stroke->fill = nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -659,7 +659,7 @@ static void _addReverseLeft(SwStroke& stroke, bool opened)
|
|||
}
|
||||
|
||||
|
||||
static void _beginSubPath(SwStroke& stroke, const SwPoint& to, bool opened)
|
||||
static void _beginSubPath(SwStroke& stroke, const SwPoint& to, bool closed)
|
||||
{
|
||||
/* We cannot process the first point because there is not enough
|
||||
information regarding its corner/cap. Later, it will be processed
|
||||
|
@ -667,14 +667,14 @@ static void _beginSubPath(SwStroke& stroke, const SwPoint& to, bool opened)
|
|||
|
||||
stroke.firstPt = true;
|
||||
stroke.center = to;
|
||||
stroke.openSubPath = opened;
|
||||
stroke.closedSubPath = closed;
|
||||
|
||||
/* Determine if we need to check whether the border radius is greater
|
||||
than the radius of curvature of a curve, to handle this case specially.
|
||||
This is only required if bevel joins or butt caps may be created because
|
||||
round & miter joins and round & square caps cover the nagative sector
|
||||
created with wide strokes. */
|
||||
if ((stroke.join != StrokeJoin::Round) || (stroke.openSubPath && stroke.cap == StrokeCap::Butt))
|
||||
if ((stroke.join != StrokeJoin::Round) || (!stroke.closedSubPath && stroke.cap == StrokeCap::Butt))
|
||||
stroke.handleWideStrokes = true;
|
||||
else
|
||||
stroke.handleWideStrokes = false;
|
||||
|
@ -686,26 +686,7 @@ static void _beginSubPath(SwStroke& stroke, const SwPoint& to, bool opened)
|
|||
|
||||
static void _endSubPath(SwStroke& stroke)
|
||||
{
|
||||
if (stroke.openSubPath) {
|
||||
auto right = stroke.borders;
|
||||
|
||||
/* all right, this is an opened path, we need to add a cap between
|
||||
right & left, add the reverse of left, then add a final cap
|
||||
between left & right */
|
||||
_addCap(stroke, stroke.angleIn, 0);
|
||||
|
||||
//add reversed points from 'left' to 'right'
|
||||
_addReverseLeft(stroke, true);
|
||||
|
||||
//now add the final cap
|
||||
stroke.center = stroke.ptStartSubPath;
|
||||
_addCap(stroke, stroke.subPathAngle + SW_ANGLE_PI, 0);
|
||||
|
||||
/* now end the right subpath accordingly. The left one is rewind
|
||||
and deosn't need further processing */
|
||||
_borderClose(right, false);
|
||||
} else {
|
||||
|
||||
if (stroke.closedSubPath) {
|
||||
//close the path if needed
|
||||
if (stroke.center != stroke.ptStartSubPath)
|
||||
_lineTo(stroke, stroke.ptStartSubPath);
|
||||
|
@ -729,6 +710,24 @@ static void _endSubPath(SwStroke& stroke)
|
|||
|
||||
_borderClose(stroke.borders + 0, false);
|
||||
_borderClose(stroke.borders + 1, true);
|
||||
} else {
|
||||
auto right = stroke.borders;
|
||||
|
||||
/* all right, this is an opened path, we need to add a cap between
|
||||
right & left, add the reverse of left, then add a final cap
|
||||
between left & right */
|
||||
_addCap(stroke, stroke.angleIn, 0);
|
||||
|
||||
//add reversed points from 'left' to 'right'
|
||||
_addReverseLeft(stroke, true);
|
||||
|
||||
//now add the final cap
|
||||
stroke.center = stroke.ptStartSubPath;
|
||||
_addCap(stroke, stroke.subPathAngle + SW_ANGLE_PI, 0);
|
||||
|
||||
/* now end the right subpath accordingly. The left one is rewind
|
||||
and deosn't need further processing */
|
||||
_borderClose(right, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -870,7 +869,9 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline)
|
|||
//A contour cannot start with a cubic control point
|
||||
if (type == SW_CURVE_TYPE_CUBIC) return false;
|
||||
|
||||
_beginSubPath(*stroke, start, outline.opened);
|
||||
auto closed = outline.closed ? outline.closed[i]: false;
|
||||
|
||||
_beginSubPath(*stroke, start, closed);
|
||||
|
||||
while (pt < limit) {
|
||||
++pt;
|
||||
|
|
Loading…
Add table
Reference in a new issue