diff options
Diffstat (limited to 'thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp')
-rw-r--r-- | thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp | 180 |
1 files changed, 139 insertions, 41 deletions
diff --git a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp index 63e7fc9447..50dec208b2 100644 --- a/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp +++ b/thirdparty/thorvg/src/lib/sw_engine/tvgSwRle.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved. * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -773,60 +773,59 @@ static int _genRle(RleWorker& rw) } -SwSpan* _intersectSpansRegion(const SwRleData *clip, const SwRleData *targetRle, SwSpan *outSpans, uint32_t spanCnt) +static SwSpan* _intersectSpansRegion(const SwRleData *clip, const SwRleData *target, SwSpan *outSpans, uint32_t outSpansCnt) { auto out = outSpans; - auto spans = targetRle->spans; - auto end = targetRle->spans + targetRle->size; + auto spans = target->spans; + auto end = target->spans + target->size; auto clipSpans = clip->spans; auto clipEnd = clip->spans + clip->size; - while (spanCnt > 0 && spans < end) { - if (clipSpans == clipEnd) { - spans = end; - break; - } + while (spans < end && clipSpans < clipEnd) { + //align y cooridnates. if (clipSpans->y > spans->y) { ++spans; continue; } - if (spans->y != clipSpans->y) { + if (spans->y > clipSpans->y) { ++clipSpans; continue; } - auto sx1 = spans->x; - auto sx2 = sx1 + spans->len; - auto cx1 = clipSpans->x; - auto cx2 = cx1 + clipSpans->len; - if (cx1 < sx1 && cx2 < sx1) { - ++clipSpans; - continue; - } - else if (sx1 < cx1 && sx2 < cx1) { - ++spans; - continue; - } - auto x = sx1 > cx1 ? sx1 : cx1; - auto len = (sx2 < cx2 ? sx2 : cx2) - x; - if (len) { - auto spansCorverage = spans->coverage; - auto clipSpansCoverage = clipSpans->coverage; - out->x = sx1 > cx1 ? sx1 : cx1; - out->len = (sx2 < cx2 ? sx2 : cx2) - out->x; - out->y = spans->y; - out->coverage = (uint8_t)(((spansCorverage * clipSpansCoverage) + 0xff) >> 8); - ++out; - --spanCnt; + //Try clipping with all clip spans which have a same y coordinate. + auto temp = clipSpans; + while(temp < clipEnd && outSpansCnt > 0 && temp->y == clipSpans->y) { + auto sx1 = spans->x; + auto sx2 = sx1 + spans->len; + auto cx1 = temp->x; + auto cx2 = cx1 + temp->len; + + //The span must be left(x1) to right(x2) direction. Not intersected. + if (cx2 < sx1 || sx2 < cx1) { + ++temp; + continue; + } + + //clip span region. + auto x = sx1 > cx1 ? sx1 : cx1; + auto len = (sx2 < cx2 ? sx2 : cx2) - x; + if (len > 0) { + out->x = x; + out->y = temp->y; + out->len = len; + out->coverage = (uint8_t)(((spans->coverage * temp->coverage) + 0xff) >> 8); + ++out; + --outSpansCnt; + } + ++temp; } - if (sx2 < cx2) ++spans; - else ++clipSpans; + ++spans; } return out; } -SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSpan *outSpans, uint32_t spanCnt) +static SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSpan *outSpans, uint32_t outSpansCnt) { auto out = outSpans; auto spans = targetRle->spans; @@ -836,7 +835,7 @@ SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSp auto maxx = minx + static_cast<int16_t>(bbox->max.x - bbox->min.x) - 1; auto maxy = miny + static_cast<int16_t>(bbox->max.y - bbox->min.y) - 1; - while (spanCnt && spans < end) { + while (outSpansCnt > 0 && spans < end) { if (spans->y > maxy) { spans = end; break; @@ -853,18 +852,58 @@ SwSpan* _intersectSpansRect(const SwBBox *bbox, const SwRleData *targetRle, SwSp out->x = spans->x; out->len = spans->len < (maxx - spans->x + 1) ? spans->len : (maxx - spans->x + 1); } - if (out->len != 0) { + if (out->len > 0) { out->y = spans->y; out->coverage = spans->coverage; ++out; + --outSpansCnt; } ++spans; - --spanCnt; } return out; } +static SwSpan* _mergeSpansRegion(const SwRleData *clip1, const SwRleData *clip2, SwSpan *outSpans) +{ + auto out = outSpans; + auto spans1 = clip1->spans; + auto end1 = clip1->spans + clip1->size; + auto spans2 = clip2->spans; + auto end2 = clip2->spans + clip2->size; + + //list two spans up in y order + //TODO: Remove duplicated regions? + while (spans1 < end1 && spans2 < end2) { + while (spans1 < end1 && spans1->y <= spans2->y) { + *out = *spans1; + ++spans1; + ++out; + } + if (spans1 >= end1) break; + while (spans2 < end2 && spans2->y <= spans1->y) { + *out = *spans2; + ++spans2; + ++out; + } + } + + //Leftovers + while (spans1 < end1) { + *out = *spans1; + ++spans1; + ++out; + } + while (spans2 < end2) { + *out = *spans2; + ++spans2; + ++out; + } + + return out; +} + + void _replaceClipSpan(SwRleData *rle, SwSpan* clippedSpans, uint32_t size) { free(rle->spans); @@ -1001,6 +1040,28 @@ error: } +SwRleData* rleRender(const SwBBox* bbox) +{ + auto width = static_cast<uint16_t>(bbox->max.x - bbox->min.x); + auto height = static_cast<uint16_t>(bbox->max.y - bbox->min.y); + + auto rle = static_cast<SwRleData*>(malloc(sizeof(SwRleData))); + rle->spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * height)); + rle->size = height; + rle->alloc = height; + + auto span = rle->spans; + for (uint16_t i = 0; i < height; ++i, ++span) { + span->x = bbox->min.x; + span->y = bbox->min.y + i; + span->len = width; + span->coverage = 255; + } + + return rle; +} + + void rleReset(SwRleData* rle) { if (!rle) return; @@ -1016,12 +1077,50 @@ void rleFree(SwRleData* rle) } +void rleMerge(SwRleData* rle, SwRleData* clip1, SwRleData* clip2) +{ + if (!rle || (!clip1 && !clip2)) return; + if (clip1 && clip1->size == 0 && clip2 && clip2->size == 0) return; + + TVGLOG("SW_ENGINE", "Unifying Rle!"); + + //clip1 is empty, just copy clip2 + if (!clip1 || clip1->size == 0) { + if (clip2) { + auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (clip2->size))); + memcpy(spans, clip2->spans, clip2->size); + _replaceClipSpan(rle, spans, clip2->size); + } else { + _replaceClipSpan(rle, nullptr, 0); + } + return; + } + + //clip2 is empty, just copy clip1 + if (!clip2 || clip2->size == 0) { + if (clip1) { + auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (clip1->size))); + memcpy(spans, clip1->spans, clip1->size); + _replaceClipSpan(rle, spans, clip1->size); + } else { + _replaceClipSpan(rle, nullptr, 0); + } + return; + } + + auto spanCnt = clip1->size + clip2->size; + auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * spanCnt)); + auto spansEnd = _mergeSpansRegion(clip1, clip2, spans); + + _replaceClipSpan(rle, spans, spansEnd - spans); +} + + void rleClipPath(SwRleData *rle, const SwRleData *clip) { if (rle->size == 0 || clip->size == 0) return; auto spanCnt = rle->size > clip->size ? rle->size : clip->size; auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt))); - if (!spans) return; auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt); _replaceClipSpan(rle, spans, spansEnd - spans); @@ -1034,7 +1133,6 @@ void rleClipRect(SwRleData *rle, const SwBBox* clip) { if (rle->size == 0) return; auto spans = static_cast<SwSpan*>(malloc(sizeof(SwSpan) * (rle->size))); - if (!spans) return; auto spansEnd = _intersectSpansRect(clip, rle, spans, rle->size); _replaceClipSpan(rle, spans, spansEnd - spans); |