sw_engine: fix too small memory of spans

In some clipping cases, the memory allocated for storing spans
was too small. As a result, the entire clipped area might not
have been rendered.
This has been resolved by conditionally increasing the memory
allocation when needed.

@Issue: https://github.com/thorvg/thorvg/issues/3461
This commit is contained in:
Mira Grudzinska 2025-05-21 00:23:55 +02:00
parent 633bcd3176
commit 844fd050bc

View file

@ -737,8 +737,9 @@ static bool _genRle(RleWorker& rw)
} }
static SwSpan* _intersectSpansRegion(const SwRle *clip, const SwRle *target, SwSpan *outSpans, uint32_t outSpansCnt) static uint32_t _intersectSpansRegion(const SwRle *clip, const SwRle *target, SwSpan *&outSpans, uint32_t outSpansAlloc)
{ {
auto outSpansCnt = 0;
auto out = outSpans; auto out = outSpans;
auto spans = target->spans; auto spans = target->spans;
auto end = target->spans + target->size; auto end = target->spans + target->size;
@ -758,7 +759,7 @@ static SwSpan* _intersectSpansRegion(const SwRle *clip, const SwRle *target, SwS
//Try clipping with all clip spans which have a same y-coordinate. //Try clipping with all clip spans which have a same y-coordinate.
auto temp = clipSpans; auto temp = clipSpans;
while(temp < clipEnd && outSpansCnt > 0 && temp->y == clipSpans->y) { while(temp < clipEnd && temp->y == clipSpans->y) {
auto sx1 = spans->x; auto sx1 = spans->x;
auto sx2 = sx1 + spans->len; auto sx2 = sx1 + spans->len;
auto cx1 = temp->x; auto cx1 = temp->x;
@ -774,22 +775,27 @@ static SwSpan* _intersectSpansRegion(const SwRle *clip, const SwRle *target, SwS
auto x = sx1 > cx1 ? sx1 : cx1; auto x = sx1 > cx1 ? sx1 : cx1;
auto len = (sx2 < cx2 ? sx2 : cx2) - x; auto len = (sx2 < cx2 ? sx2 : cx2) - x;
if (len > 0) { if (len > 0) {
if (outSpansCnt == outSpansAlloc) {
outSpansAlloc *= 2;
outSpans = tvg::realloc<SwSpan*>(outSpans, sizeof(SwSpan) * outSpansAlloc);
out = outSpans + outSpansCnt;
}
out->x = x; out->x = x;
out->y = temp->y; out->y = temp->y;
out->len = len; out->len = len;
out->coverage = (uint8_t)(((spans->coverage * temp->coverage) + 0xff) >> 8); out->coverage = (uint8_t)(((spans->coverage * temp->coverage) + 0xff) >> 8);
++out; ++out;
--outSpansCnt; ++outSpansCnt;
} }
++temp; ++temp;
} }
++spans; ++spans;
} }
return out; return outSpansCnt;
} }
static SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRle *targetRle, SwSpan *outSpans, uint32_t outSpansCnt) static uint32_t _intersectSpansRect(const SwBBox *bbox, const SwRle *targetRle, SwSpan *outSpans, uint32_t outSpansCnt)
{ {
auto out = outSpans; auto out = outSpans;
auto spans = targetRle->spans; auto spans = targetRle->spans;
@ -824,7 +830,7 @@ static SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRle *targetRle, S
} }
++spans; ++spans;
} }
return out; return out - outSpans;
} }
@ -997,11 +1003,11 @@ void rleFree(SwRle* rle)
bool rleClip(SwRle *rle, const SwRle *clip) bool rleClip(SwRle *rle, const SwRle *clip)
{ {
if (rle->size == 0 || clip->size == 0) return false; if (rle->size == 0 || clip->size == 0) return false;
auto spanCnt = rle->size > clip->size ? rle->size : clip->size; auto spanAlloc = rle->size > clip->size ? rle->size : clip->size;
auto spans = tvg::malloc<SwSpan*>(sizeof(SwSpan) * (spanCnt)); auto spans = tvg::malloc<SwSpan*>(sizeof(SwSpan) * spanAlloc);
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt); auto spanCnt = _intersectSpansRegion(clip, rle, spans, spanAlloc);
_replaceClipSpan(rle, spans, spansEnd - spans); _replaceClipSpan(rle, spans, spanCnt);
TVGLOG("SW_ENGINE", "Using Path Clipping!"); TVGLOG("SW_ENGINE", "Using Path Clipping!");
@ -1013,9 +1019,9 @@ bool rleClip(SwRle *rle, const SwBBox* clip)
{ {
if (rle->size == 0) return false; if (rle->size == 0) return false;
auto spans = tvg::malloc<SwSpan*>(sizeof(SwSpan) * (rle->size)); auto spans = tvg::malloc<SwSpan*>(sizeof(SwSpan) * (rle->size));
auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size); auto spanCnt = _intersectSpansRect(clip, rle, spans, rle->size);
_replaceClipSpan(rle, spans, spansEnd - spans); _replaceClipSpan(rle, spans, spanCnt);
TVGLOG("SW_ENGINE", "Using Box Clipping!"); TVGLOG("SW_ENGINE", "Using Box Clipping!");