From fbc55d8d6cf977735ae0209e484707a716239083 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Thu, 12 Aug 2021 13:09:47 +0900 Subject: [PATCH] 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 --- src/lib/sw_engine/tvgSwCommon.h | 4 ++-- src/lib/sw_engine/tvgSwImage.cpp | 20 +++++++++------- src/lib/sw_engine/tvgSwMemPool.cpp | 6 +++++ src/lib/sw_engine/tvgSwShape.cpp | 37 ++++++++++++++++++---------- src/lib/sw_engine/tvgSwStroke.cpp | 49 +++++++++++++++++++------------------- 5 files changed, 69 insertions(+), 47 deletions(-) diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index b90b523..0fb59d3 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -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; }; diff --git a/src/lib/sw_engine/tvgSwImage.cpp b/src/lib/sw_engine/tvgSwImage.cpp index 0de743d..7a9ad4d 100644 --- a/src/lib/sw_engine/tvgSwImage.cpp +++ b/src/lib/sw_engine/tvgSwImage.cpp @@ -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(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint))); - outline->types = static_cast(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t))); - - outline->reservedCntrsCnt = 1; - outline->cntrs = static_cast(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t))); + if (outline->reservedPtsCnt < 5) { + outline->reservedPtsCnt = 5; + outline->pts = static_cast(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint))); + outline->types = static_cast(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t))); + } + + if (outline->reservedCntrsCnt < 1) { + outline->reservedCntrsCnt = 1; + outline->cntrs = static_cast(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t))); + outline->closed = static_cast(realloc(outline->closed, outline->reservedCntrsCnt * sizeof(bool))); + outline->closed[0] = true; + } auto w = static_cast(image->w); auto h = static_cast(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; diff --git a/src/lib/sw_engine/tvgSwMemPool.cpp b/src/lib/sw_engine/tvgSwMemPool.cpp index ae051d8..ab622b1 100644 --- a/src/lib/sw_engine/tvgSwMemPool.cpp +++ b/src/lib/sw_engine/tvgSwMemPool.cpp @@ -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; } diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 4dcaa95..7f8ec81 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -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(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(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(pattern); dash.outline = static_cast(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; -} \ No newline at end of file +} diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index a39d005..dda4a9b 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -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; -- 2.7.4