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 ptsCnt; //number of points in the glyph
|
||||||
uint32_t reservedPtsCnt;
|
uint32_t reservedPtsCnt;
|
||||||
uint8_t* types; //curve type
|
uint8_t* types; //curve type
|
||||||
|
bool* closed; //opened or closed path?
|
||||||
FillRule fillRule;
|
FillRule fillRule;
|
||||||
bool opened; //opened path?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SwSpan
|
struct SwSpan
|
||||||
|
@ -190,7 +190,7 @@ struct SwStroke
|
||||||
float sx, sy;
|
float sx, sy;
|
||||||
|
|
||||||
bool firstPt;
|
bool firstPt;
|
||||||
bool openSubPath;
|
bool closedSubPath;
|
||||||
bool handleWideStrokes;
|
bool handleWideStrokes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,12 +31,18 @@ static bool _genOutline(SwImage* image, const Matrix* transform, SwMpool* mpool,
|
||||||
image->outline = mpoolReqOutline(mpool, tid);
|
image->outline = mpoolReqOutline(mpool, tid);
|
||||||
auto outline = image->outline;
|
auto outline = image->outline;
|
||||||
|
|
||||||
outline->reservedPtsCnt = 5;
|
if (outline->reservedPtsCnt < 5) {
|
||||||
outline->pts = static_cast<SwPoint*>(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint)));
|
outline->reservedPtsCnt = 5;
|
||||||
outline->types = static_cast<uint8_t*>(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t)));
|
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;
|
if (outline->reservedCntrsCnt < 1) {
|
||||||
outline->cntrs = static_cast<uint32_t*>(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t)));
|
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 w = static_cast<float>(image->w);
|
||||||
auto h = static_cast<float>(image->h);
|
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->cntrs[outline->cntrsCnt] = outline->ptsCnt - 1;
|
||||||
++outline->cntrsCnt;
|
++outline->cntrsCnt;
|
||||||
|
|
||||||
outline->opened = false;
|
|
||||||
|
|
||||||
image->outline = outline;
|
image->outline = outline;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -107,6 +107,9 @@ bool mpoolClear(SwMpool* mpool)
|
||||||
free(p->types);
|
free(p->types);
|
||||||
p->types = nullptr;
|
p->types = nullptr;
|
||||||
|
|
||||||
|
free(p->closed);
|
||||||
|
p->closed = nullptr;
|
||||||
|
|
||||||
p->cntrsCnt = p->reservedCntrsCnt = 0;
|
p->cntrsCnt = p->reservedCntrsCnt = 0;
|
||||||
p->ptsCnt = p->reservedPtsCnt = 0;
|
p->ptsCnt = p->reservedPtsCnt = 0;
|
||||||
|
|
||||||
|
@ -122,6 +125,9 @@ bool mpoolClear(SwMpool* mpool)
|
||||||
free(p->types);
|
free(p->types);
|
||||||
p->types = nullptr;
|
p->types = nullptr;
|
||||||
|
|
||||||
|
free(p->closed);
|
||||||
|
p->closed = nullptr;
|
||||||
|
|
||||||
p->cntrsCnt = p->reservedCntrsCnt = 0;
|
p->cntrsCnt = p->reservedCntrsCnt = 0;
|
||||||
p->ptsCnt = p->reservedPtsCnt = 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.reservedCntrsCnt = outline.cntrsCnt + n;
|
||||||
outline.cntrs = static_cast<uint32_t*>(realloc(outline.cntrs, outline.reservedCntrsCnt * sizeof(uint32_t)));
|
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)
|
static void _outlineEnd(SwOutline& outline)
|
||||||
{
|
{
|
||||||
_growOutlineContour(outline, 1);
|
_growOutlineContour(outline, 1);
|
||||||
|
|
||||||
|
if (outline.closed) {
|
||||||
|
outline.closed[outline.cntrsCnt] = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (outline.ptsCnt > 0) {
|
if (outline.ptsCnt > 0) {
|
||||||
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
|
outline.cntrs[outline.cntrsCnt] = outline.ptsCnt - 1;
|
||||||
++outline.cntrsCnt;
|
++outline.cntrsCnt;
|
||||||
|
@ -142,7 +156,7 @@ static void _outlineClose(SwOutline& outline)
|
||||||
|
|
||||||
//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.ptsCnt == i) {
|
if (outline.ptsCnt == i) {
|
||||||
outline.opened = true;
|
outline.closed[outline.cntrsCnt] = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +167,7 @@ static void _outlineClose(SwOutline& outline)
|
||||||
outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
|
outline.types[outline.ptsCnt] = SW_CURVE_TYPE_POINT;
|
||||||
++outline.ptsCnt;
|
++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???
|
//OPTMIZE ME: Use mempool???
|
||||||
dash.pattern = const_cast<float*>(pattern);
|
dash.pattern = const_cast<float*>(pattern);
|
||||||
dash.outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
|
dash.outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
|
||||||
dash.outline->opened = true;
|
|
||||||
|
|
||||||
//smart reservation
|
//smart reservation
|
||||||
auto outlinePtsCnt = 0;
|
auto outlinePtsCnt = 0;
|
||||||
|
@ -305,7 +318,7 @@ static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
|
||||||
++outlinePtsCnt; //for close
|
++outlinePtsCnt; //for close
|
||||||
++outlineCntrsCnt; //for end
|
++outlineCntrsCnt; //for end
|
||||||
|
|
||||||
//Reserve Approximitely 20x...
|
//No idea exact count.... Reserve Approximitely 20x...
|
||||||
_growOutlinePoint(*dash.outline, outlinePtsCnt * 20);
|
_growOutlinePoint(*dash.outline, outlinePtsCnt * 20);
|
||||||
_growOutlineContour(*dash.outline, outlineCntrsCnt * 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);
|
shape->outline = mpoolReqOutline(mpool, tid);
|
||||||
auto outline = shape->outline;
|
auto outline = shape->outline;
|
||||||
outline->opened = true;
|
|
||||||
|
|
||||||
_growOutlinePoint(*outline, outlinePtsCnt);
|
_growOutlinePoint(*outline, outlinePtsCnt);
|
||||||
_growOutlineContour(*outline, outlineCntrsCnt);
|
|
||||||
|
|
||||||
auto closed = false;
|
if (_growOutlineContour(*outline, outlineCntrsCnt)) {
|
||||||
|
_growOutlineClose(*outline);
|
||||||
|
}
|
||||||
|
|
||||||
//Generate Outlines
|
//Generate Outlines
|
||||||
while (cmdCnt-- > 0) {
|
while (cmdCnt-- > 0) {
|
||||||
switch(*cmds) {
|
switch(*cmds) {
|
||||||
case PathCommand::Close: {
|
case PathCommand::Close: {
|
||||||
_outlineClose(*outline);
|
_outlineClose(*outline);
|
||||||
closed = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PathCommand::MoveTo: {
|
case PathCommand::MoveTo: {
|
||||||
|
@ -442,8 +454,6 @@ static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transf
|
||||||
|
|
||||||
_outlineEnd(*outline);
|
_outlineEnd(*outline);
|
||||||
|
|
||||||
if (closed) outline->opened = false;
|
|
||||||
|
|
||||||
outline->fillRule = sdata->fillRule();
|
outline->fillRule = sdata->fillRule();
|
||||||
shape->outline = outline;
|
shape->outline = outline;
|
||||||
|
|
||||||
|
@ -587,6 +597,7 @@ fail:
|
||||||
if (shapeOutline->cntrs) free(shapeOutline->cntrs);
|
if (shapeOutline->cntrs) free(shapeOutline->cntrs);
|
||||||
if (shapeOutline->pts) free(shapeOutline->pts);
|
if (shapeOutline->pts) free(shapeOutline->pts);
|
||||||
if (shapeOutline->types) free(shapeOutline->types);
|
if (shapeOutline->types) free(shapeOutline->types);
|
||||||
|
if (shapeOutline->closed) free(shapeOutline->closed);
|
||||||
free(shapeOutline);
|
free(shapeOutline);
|
||||||
}
|
}
|
||||||
mpoolRetStrokeOutline(mpool, tid);
|
mpoolRetStrokeOutline(mpool, tid);
|
||||||
|
@ -640,4 +651,4 @@ void shapeDelStrokeFill(SwShape* shape)
|
||||||
if (!shape->stroke->fill) return;
|
if (!shape->stroke->fill) return;
|
||||||
fillFree(shape->stroke->fill);
|
fillFree(shape->stroke->fill);
|
||||||
shape->stroke->fill = nullptr;
|
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
|
/* We cannot process the first point because there is not enough
|
||||||
information regarding its corner/cap. Later, it will be processed
|
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.firstPt = true;
|
||||||
stroke.center = to;
|
stroke.center = to;
|
||||||
stroke.openSubPath = opened;
|
stroke.closedSubPath = closed;
|
||||||
|
|
||||||
/* Determine if we need to check whether the border radius is greater
|
/* 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.
|
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
|
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
|
round & miter joins and round & square caps cover the nagative sector
|
||||||
created with wide strokes. */
|
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;
|
stroke.handleWideStrokes = true;
|
||||||
else
|
else
|
||||||
stroke.handleWideStrokes = false;
|
stroke.handleWideStrokes = false;
|
||||||
|
@ -686,26 +686,7 @@ static void _beginSubPath(SwStroke& stroke, const SwPoint& to, bool opened)
|
||||||
|
|
||||||
static void _endSubPath(SwStroke& stroke)
|
static void _endSubPath(SwStroke& stroke)
|
||||||
{
|
{
|
||||||
if (stroke.openSubPath) {
|
if (stroke.closedSubPath) {
|
||||||
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 {
|
|
||||||
|
|
||||||
//close the path if needed
|
//close the path if needed
|
||||||
if (stroke.center != stroke.ptStartSubPath)
|
if (stroke.center != stroke.ptStartSubPath)
|
||||||
_lineTo(stroke, stroke.ptStartSubPath);
|
_lineTo(stroke, stroke.ptStartSubPath);
|
||||||
|
@ -729,6 +710,24 @@ static void _endSubPath(SwStroke& stroke)
|
||||||
|
|
||||||
_borderClose(stroke.borders + 0, false);
|
_borderClose(stroke.borders + 0, false);
|
||||||
_borderClose(stroke.borders + 1, true);
|
_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
|
//A contour cannot start with a cubic control point
|
||||||
if (type == SW_CURVE_TYPE_CUBIC) return false;
|
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) {
|
while (pt < limit) {
|
||||||
++pt;
|
++pt;
|
||||||
|
|
Loading…
Add table
Reference in a new issue