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 rleFree(SwRle* rle);
void rleReset(SwRle* rle); void rleReset(SwRle* rle);
void rleMerge(SwRle* rle, SwRle* clip1, SwRle* clip2); void rleMerge(SwRle* rle, SwRle* clip1, SwRle* clip2);
void rleClip(SwRle* rle, const SwRle* clip); bool rleClip(SwRle* rle, const SwRle* clip);
void rleClip(SwRle* rle, const SwBBox* clip); bool rleClip(SwRle* rle, const SwBBox* clip);
SwMpool* mpoolInit(uint32_t threads); SwMpool* mpoolInit(uint32_t threads);
bool mpoolTerm(SwMpool* mpool); bool mpoolTerm(SwMpool* mpool);

View file

@ -103,11 +103,9 @@ struct SwShapeTask : SwTask
bool clip(SwRle* target) override bool clip(SwRle* target) override
{ {
if (shape.fastTrack) rleClip(target, &bbox); if (shape.fastTrack) return rleClip(target, &bbox);
else if (shape.rle) rleClip(target, shape.rle); else if (shape.rle) return rleClip(target, shape.rle);
else return false; return false;
return true;
} }
void run(unsigned tid) override void run(unsigned tid) override
@ -176,10 +174,8 @@ struct SwShapeTask : SwTask
//Clip Path //Clip Path
for (auto clip = clips.begin(); clip < clips.end(); ++clip) { for (auto clip = clips.begin(); clip < clips.end(); ++clip) {
auto clipper = static_cast<SwTask*>(*clip); auto clipper = static_cast<SwTask*>(*clip);
//Clip shape rle if (shape.rle && !clipper->clip(shape.rle)) goto err; //Clip shape rle
if (shape.rle && !clipper->clip(shape.rle)) goto err; if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err; //Clip stroke rle
//Clip stroke rle
if (shape.strokeRle && !clipper->clip(shape.strokeRle)) goto err;
} }
bbox = renderRegion; //sync 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 spanCnt = rle->size > clip->size ? rle->size : clip->size;
auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt))); auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt)));
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt); auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt);
@ -1030,17 +1030,21 @@ void rleClip(SwRle *rle, const SwRle *clip)
_replaceClipSpan(rle, spans, spansEnd - spans); _replaceClipSpan(rle, spans, spansEnd - spans);
TVGLOG("SW_ENGINE", "Using Path Clipping!"); 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 spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (rle->size)));
auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size); auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size);
_replaceClipSpan(rle, spans, spansEnd - spans); _replaceClipSpan(rle, spans, spansEnd - spans);
TVGLOG("SW_ENGINE", "Using Box Clipping!"); TVGLOG("SW_ENGINE", "Using Box Clipping!");
return true;
} }