common: order(bool strokeFirst) api introduced

The new api is introduced to handle the rendering
order of a stroke and a fill. By default fill is
rendered as the first one, stroke as the second
one. This order can be reversed by calling
order(true).

@Issue: https://github.com/thorvg/thorvg/issues/1340
This commit is contained in:
Mira Grudzinska 2023-04-05 02:25:14 +02:00 committed by Hermet Park
parent e61857f27d
commit 69a9583354
5 changed files with 64 additions and 19 deletions

View file

@ -977,6 +977,18 @@ public:
*/ */
Result fill(FillRule r) noexcept; Result fill(FillRule r) noexcept;
/**
* @brief Sets the rendering order of the stroke and the fill.
*
* @param[in] strokeFirst If @c true the stroke is rendered before the fill, otherwise the stroke is rendered as the second one (the default option).
*
* @return Result::Success when succeed, Result::FailedAllocation otherwise.
* @BETA_API
*/
Result order(bool strokeFirst) noexcept;
/** /**
* @brief Gets the commands data of the path. * @brief Gets the commands data of the path.
* *

View file

@ -96,7 +96,7 @@ struct SwShapeTask : SwTask
} }
void run(unsigned tid) override void run(unsigned tid) override
{ {
if (opacity == 0 && !clipper) return; //Invisible if (opacity == 0 && !clipper) return; //Invisible
uint8_t strokeAlpha = 0; uint8_t strokeAlpha = 0;
@ -136,7 +136,7 @@ struct SwShapeTask : SwTask
shape outline below stroke could be full covered by stroke drawing. shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition. Thus it turns off antialising in that condition.
Also, it shouldn't be dash style. */ Also, it shouldn't be dash style. */
auto antiAlias = (strokeAlpha == 255 && rshape->strokeWidth() > 2 && rshape->strokeDash(nullptr) == 0) ? false : true; auto antiAlias = strokeAlpha < 255 || rshape->strokeWidth() <= 2 || rshape->strokeDash(nullptr) > 0 || (rshape->stroke && rshape->stroke->strokeFirst);
if (!shapeGenRle(&shape, rshape, antiAlias)) goto err; if (!shapeGenRle(&shape, rshape, antiAlias)) goto err;
} }
@ -322,6 +322,31 @@ static void _termEngine()
} }
static void _renderFill(SwShapeTask* task, SwSurface* surface, uint32_t opacity)
{
uint8_t r, g, b, a;
if (auto fill = task->rshape->fill) {
rasterGradientShape(surface, &task->shape, fill->identifier());
} else {
task->rshape->fillColor(&r, &g, &b, &a);
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterShape(surface, &task->shape, r, g, b, a);
}
}
static void _renderStroke(SwShapeTask* task, SwSurface* surface, uint32_t opacity)
{
uint8_t r, g, b, a;
if (auto strokeFill = task->rshape->strokeFill()) {
rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
} else {
if (task->rshape->strokeColor(&r, &g, &b, &a)) {
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
}
}
}
/************************************************************************/ /************************************************************************/
/* External Class Implementation */ /* External Class Implementation */
/************************************************************************/ /************************************************************************/
@ -482,23 +507,12 @@ bool SwRenderer::renderShape(RenderData data)
} }
//Main raster stage //Main raster stage
uint8_t r, g, b, a; if (task->rshape->stroke && task->rshape->stroke->strokeFirst) {
_renderStroke(task, surface, opacity);
if (auto fill = task->rshape->fill) { _renderFill(task, surface, opacity);
rasterGradientShape(surface, &task->shape, fill->identifier());
} else { } else {
task->rshape->fillColor(&r, &g, &b, &a); _renderFill(task, surface, opacity);
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255); _renderStroke(task, surface, opacity);
if (a > 0) rasterShape(surface, &task->shape, r, g, b, a);
}
if (auto strokeFill = task->rshape->strokeFill()) {
rasterGradientStroke(surface, &task->shape, strokeFill->identifier());
} else {
if (task->rshape->strokeColor(&r, &g, &b, &a)) {
a = static_cast<uint8_t>((opacity * (uint32_t) a) / 255);
if (a > 0) rasterStroke(surface, &task->shape, r, g, b, a);
}
} }
if (task->cmpStroking) endComposite(cmp); if (task->cmpStroking) endComposite(cmp);

View file

@ -94,6 +94,7 @@ struct RenderStroke
uint32_t dashCnt = 0; uint32_t dashCnt = 0;
StrokeCap cap = StrokeCap::Square; StrokeCap cap = StrokeCap::Square;
StrokeJoin join = StrokeJoin::Bevel; StrokeJoin join = StrokeJoin::Bevel;
bool strokeFirst = false;
~RenderStroke() ~RenderStroke()
{ {

View file

@ -288,6 +288,14 @@ const Fill* Shape::fill() const noexcept
} }
Result Shape::order(bool strokeFirst) noexcept
{
if (!pImpl->strokeFirst(strokeFirst)) return Result::FailedAllocation;
return Result::Success;
}
Result Shape::stroke(float width) noexcept Result Shape::stroke(float width) noexcept
{ {
if (!pImpl->strokeWidth(width)) return Result::FailedAllocation; if (!pImpl->strokeWidth(width)) return Result::FailedAllocation;
@ -390,4 +398,4 @@ Result Shape::fill(FillRule r) noexcept
FillRule Shape::fillRule() const noexcept FillRule Shape::fillRule() const noexcept
{ {
return pImpl->rs.rule; return pImpl->rs.rule;
} }

View file

@ -262,6 +262,15 @@ struct Shape::Impl
return true; return true;
} }
bool strokeFirst(bool strokeFirst)
{
if (!rs.stroke) rs.stroke = new RenderStroke();
rs.stroke->strokeFirst = strokeFirst;
flag |= RenderUpdateFlag::Stroke;
return true;
}
Paint* duplicate() Paint* duplicate()
{ {
auto ret = Shape::gen(); auto ret = Shape::gen();
@ -295,6 +304,7 @@ struct Shape::Impl
dup->rs.stroke->dashCnt = rs.stroke->dashCnt; dup->rs.stroke->dashCnt = rs.stroke->dashCnt;
dup->rs.stroke->cap = rs.stroke->cap; dup->rs.stroke->cap = rs.stroke->cap;
dup->rs.stroke->join = rs.stroke->join; dup->rs.stroke->join = rs.stroke->join;
dup->rs.stroke->strokeFirst = rs.stroke->strokeFirst;
memcpy(dup->rs.stroke->color, rs.stroke->color, sizeof(rs.stroke->color)); memcpy(dup->rs.stroke->color, rs.stroke->color, sizeof(rs.stroke->color));
if (rs.stroke->dashCnt > 0) { if (rs.stroke->dashCnt > 0) {