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

View file

@ -96,7 +96,7 @@ struct SwShapeTask : SwTask
}
void run(unsigned tid) override
{
{
if (opacity == 0 && !clipper) return; //Invisible
uint8_t strokeAlpha = 0;
@ -136,7 +136,7 @@ struct SwShapeTask : SwTask
shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition.
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;
}
@ -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 */
/************************************************************************/
@ -482,23 +507,12 @@ bool SwRenderer::renderShape(RenderData data)
}
//Main raster stage
uint8_t r, g, b, a;
if (auto fill = task->rshape->fill) {
rasterGradientShape(surface, &task->shape, fill->identifier());
if (task->rshape->stroke && task->rshape->stroke->strokeFirst) {
_renderStroke(task, surface, opacity);
_renderFill(task, surface, opacity);
} 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);
}
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);
}
_renderFill(task, surface, opacity);
_renderStroke(task, surface, opacity);
}
if (task->cmpStroking) endComposite(cmp);

View file

@ -94,6 +94,7 @@ struct RenderStroke
uint32_t dashCnt = 0;
StrokeCap cap = StrokeCap::Square;
StrokeJoin join = StrokeJoin::Bevel;
bool strokeFirst = false;
~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
{
if (!pImpl->strokeWidth(width)) return Result::FailedAllocation;
@ -390,4 +398,4 @@ Result Shape::fill(FillRule r) noexcept
FillRule Shape::fillRule() const noexcept
{
return pImpl->rs.rule;
}
}

View file

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