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:
Hermet Park 2021-08-12 13:09:47 +09:00 committed by Hermet Park
parent 669ac392ca
commit e15b1dbc5f
5 changed files with 68 additions and 46 deletions

View file

@ -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;
};

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;