sw_engine: fixed a rendering bug when the invalid clipper is applied.

Shapes with boundaries outside the rendering area are ignored as non-visible.
The issue arises when such a shape serves as a clipper.
The expected behavior is for the entire clipee to be cut out,
but previously, the clipee remained fully visible as if no clip was applied.

The fix identifies these clippers and skips rendering clipees.

Please note that we can skip rendering at the Paint update stage
if the clipper's viewport is outside the canvas.
This optimization can improve performance, but only for this specific case.
The downside of the approach is that it disrupts multi-processing for clipper updates.
As a result, that approach was discarded.

issue: https://github.com/thorvg/thorvg/issues/3003
issue: https://github.com/thorvg/thorvg/issues/2684

Co-Authored-By: Mira Grudzinska <mira@lottiefiles.com>
This commit is contained in:
Hermet Park 2024-12-14 01:02:12 +09:00 committed by Hermet Park
parent e395961f3b
commit 01f4d6304a
3 changed files with 15 additions and 15 deletions

View file

@ -543,8 +543,8 @@ SwRle* rleRender(const SwBBox* bbox);
void rleFree(SwRle* rle);
void rleReset(SwRle* rle);
void rleMerge(SwRle* rle, SwRle* clip1, SwRle* clip2);
void rleClip(SwRle* rle, const SwRle* clip);
void rleClip(SwRle* rle, const SwBBox* clip);
bool rleClip(SwRle* rle, const SwRle* clip);
bool rleClip(SwRle* rle, const SwBBox* clip);
SwMpool* mpoolInit(uint32_t threads);
bool mpoolTerm(SwMpool* mpool);

View file

@ -103,11 +103,9 @@ struct SwShapeTask : SwTask
bool clip(SwRle* target) override
{
if (shape.fastTrack) rleClip(target, &bbox);
else if (shape.rle) rleClip(target, shape.rle);
else return false;
return true;
if (shape.fastTrack) return rleClip(target, &bbox);
else if (shape.rle) return rleClip(target, shape.rle);
return false;
}
void run(unsigned tid) override
@ -176,10 +174,8 @@ struct SwShapeTask : SwTask
//Clip Path
for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
auto clipper = static_cast<SwTask*>(*clip);
//Clip shape rle
if (shape.rle && !clipper->clip(shape.rle)) goto err;
//Clip stroke rle
if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err;
if (shape.rle && !clipper->clip(shape.rle)) goto err; //Clip shape rle
if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err; //Clip stroke rle
}
bbox = renderRegion; //sync

View file

@ -1020,9 +1020,9 @@ void rleFree(SwRle* rle)
}
void rleClip(SwRle *rle, const SwRle *clip)
bool rleClip(SwRle *rle, const SwRle *clip)
{
if (rle->size == 0 || clip->size == 0) return;
if (rle->size == 0 || clip->size == 0) return false;
auto spanCnt = rle->size > clip->size ? rle->size : clip->size;
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt)));
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt);
@ -1030,17 +1030,21 @@ void rleClip(SwRle *rle, const SwRle *clip)
_replaceClipSpan(rle, spans, spansEnd - spans);
TVGLOG("SW_ENGINE", "Using Path Clipping!");
return true;
}
void rleClip(SwRle *rle, const SwBBox* clip)
bool rleClip(SwRle *rle, const SwBBox* clip)
{
if (rle->size == 0) return;
if (rle->size == 0) return false;
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (rle->size)));
auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size);
_replaceClipSpan(rle, spans, spansEnd - spans);
TVGLOG("SW_ENGINE", "Using Box Clipping!");
return true;
}