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

View file

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

View file

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

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

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 /* 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;