From 5c94127c2d72ace9c40565f42a5b28d25984b902 Mon Sep 17 00:00:00 2001 From: Jakub Marcowski Date: Wed, 28 May 2025 00:43:14 +0200 Subject: [PATCH] thorvg: Update to 0.15.13 --- thirdparty/README.md | 3 +- thirdparty/thorvg/inc/config.h | 2 +- .../0002-png-explicit-variable-scope.patch | 13 ------- .../src/loaders/external_jpg/tvgJpgLoader.cpp | 2 +- .../thorvg/src/loaders/svg/tvgSvgLoader.cpp | 39 +++++++++++-------- .../src/loaders/svg/tvgSvgLoaderCommon.h | 2 +- .../src/loaders/svg/tvgSvgSceneBuilder.cpp | 16 ++++++-- .../src/renderer/sw_engine/tvgSwRenderer.cpp | 33 ++++++---------- .../src/renderer/sw_engine/tvgSwRle.cpp | 2 +- thirdparty/thorvg/src/renderer/tvgPaint.cpp | 15 ++++--- thirdparty/thorvg/src/renderer/tvgPaint.h | 2 +- thirdparty/thorvg/src/renderer/tvgRender.h | 7 +++- thirdparty/thorvg/src/renderer/tvgShape.h | 2 +- thirdparty/thorvg/update-thorvg.sh | 2 +- 14 files changed, 71 insertions(+), 69 deletions(-) delete mode 100644 thirdparty/thorvg/patches/0002-png-explicit-variable-scope.patch diff --git a/thirdparty/README.md b/thirdparty/README.md index 17a4397759c..cd2232166ab 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -970,7 +970,7 @@ Patches: ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.15.12 (91bd6f35b94e92abfc1a320632e66cd124943524, 2025) +- Version: 0.15.13 (c597365b99f27cb46e2a5ac2942da45bb73d5a55, 2025) - License: MIT Files extracted from upstream source: @@ -981,7 +981,6 @@ Files extracted from upstream source: Patches: - `0001-revert-tvglines-bezier-precision.patch` (GH-96658) -- `0002-png-explicit-variable-scope.patch` (GH-105093) ## tinyexr diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index e7362a986a4..59d95d11ac6 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -15,5 +15,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.15.12" +#define THORVG_VERSION_STRING "0.15.13" #endif diff --git a/thirdparty/thorvg/patches/0002-png-explicit-variable-scope.patch b/thirdparty/thorvg/patches/0002-png-explicit-variable-scope.patch deleted file mode 100644 index 4a6a91e097a..00000000000 --- a/thirdparty/thorvg/patches/0002-png-explicit-variable-scope.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp -index 71bf25a62b..c362403125 100644 ---- a/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp -+++ b/thirdparty/thorvg/src/loaders/external_png/tvgPngLoader.cpp -@@ -88,7 +88,7 @@ bool PngLoader::read() - - if (w == 0 || h == 0) return false; - -- if (cs == ColorSpace::ARGB8888 || cs == ColorSpace::ARGB8888S) { -+ if (ImageLoader::cs == ColorSpace::ARGB8888 || ImageLoader::cs == ColorSpace::ARGB8888S) { - image->format = PNG_FORMAT_BGRA; - surface.cs = ColorSpace::ARGB8888S; - } else { diff --git a/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp b/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp index f00993ab14c..1a4e7506a7c 100644 --- a/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/external_jpg/tvgJpgLoader.cpp @@ -132,7 +132,7 @@ bool JpgLoader::read() //determine the image format TJPF format; - if (cs == ColorSpace::ARGB8888 || cs == ColorSpace::ARGB8888S) { + if (ImageLoader::cs == ColorSpace::ARGB8888 || ImageLoader::cs == ColorSpace::ARGB8888S) { format = TJPF_BGRX; surface.cs = ColorSpace::ARGB8888; } else { diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index 7dac82645c5..cad68106083 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -3368,6 +3368,13 @@ static void _svgLoaderParserXmlClose(SvgLoaderData* loader, const char* content, } } + for (unsigned int i = 0; i < sizeof(gradientTags) / sizeof(gradientTags[0]); i++) { + if (!strncmp(tagName, gradientTags[i].tag, sz)) { + loader->gradientStack.pop(); + break; + } + } + for (unsigned int i = 0; i < sizeof(graphicsTags) / sizeof(graphicsTags[0]); i++) { if (!strncmp(tagName, graphicsTags[i].tag, sz)) { loader->currentGraphicsNode = nullptr; @@ -3439,7 +3446,6 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, if (node->type != SvgNodeType::Defs || !empty) { loader->stack.push(node); } - loader->latestGradient = nullptr; } else if ((method = _findGraphicsFactory(tagName))) { if (loader->stack.count > 0) parent = loader->stack.last(); else parent = loader->doc; @@ -3450,24 +3456,26 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, loader->stack.push(defs); loader->currentGraphicsNode = node; } - loader->latestGradient = nullptr; } else if ((gradientMethod = _findGradientFactory(tagName))) { SvgStyleGradient* gradient; gradient = gradientMethod(loader, attrs, attrsLength); - //FIXME: The current parsing structure does not distinguish end tags. - // There is no way to know if the currently parsed gradient is in defs. - // If a gradient is declared outside of defs after defs is set, it is included in the gradients of defs. - // But finally, the loader has a gradient style list regardless of defs. - // This is only to support this when multiple gradients are declared, even if no defs are declared. - // refer to: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs - if (loader->def && loader->doc->node.doc.defs) { - loader->def->node.defs.gradients.push(gradient); - } else { - loader->gradients.push(gradient); + //Gradients do not allow nested declarations, so only the earliest declared Gradient is valid. + if (loader->gradientStack.count == 0) { + //FIXME: The current parsing structure does not distinguish end tags. + // There is no way to know if the currently parsed gradient is in defs. + // If a gradient is declared outside of defs after defs is set, it is included in the gradients of defs. + // But finally, the loader has a gradient style list regardless of defs. + // This is only to support this when multiple gradients are declared, even if no defs are declared. + // refer to: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs + if (loader->def && loader->doc->node.doc.defs) { + loader->def->node.defs.gradients.push(gradient); + } else { + loader->gradients.push(gradient); + } } - loader->latestGradient = gradient; + if (!empty) loader->gradientStack.push(gradient); } else if (!strcmp(tagName, "stop")) { - if (!loader->latestGradient) { + if (loader->gradientStack.count == 0) { TVGLOG("SVG", "Stop element is used outside of the Gradient element"); return; } @@ -3475,9 +3483,8 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, loader->svgParse->gradStop = {0.0f, 0, 0, 0, 255}; loader->svgParse->flags = SvgStopStyleFlags::StopDefault; simpleXmlParseAttributes(attrs, attrsLength, _attrParseStops, loader); - loader->latestGradient->stops.push(loader->svgParse->gradStop); + loader->gradientStack.last()->stops.push(loader->svgParse->gradStop); } else { - loader->latestGradient = nullptr; if (!isIgnoreUnsupportedLogElements(tagName)) TVGLOG("SVG", "Unsupported elements used [Elements: %s]", tagName); } } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h index c2fcc77da58..696c84ad7d2 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoaderCommon.h @@ -577,7 +577,7 @@ struct SvgLoaderData SvgNode* def = nullptr; //also used to store nested graphic nodes SvgNode* cssStyle = nullptr; Array gradients; - SvgStyleGradient* latestGradient = nullptr; //For stops + Array gradientStack; //For stops SvgParser* svgParse = nullptr; Array cloneNodes; Array nodesToStyle; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp index 512b0ed4a45..668f7aa051b 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -752,12 +752,22 @@ static unique_ptr _useBuildHelper(SvgLoaderData& loaderData, const SvgNod } viewBoxClip->transform(mClipTransform); - scene->clip(std::move(viewBoxClip)); + auto clippingLayer = Scene::gen(); + clippingLayer->clip(std::move(viewBoxClip)); + clippingLayer->push(std::move(scene)); + return clippingLayer; } - } else { - scene->transform(mUseTransform); + return scene; } + if (auto clipper = scene->Paint::pImpl->clipper) { + auto clipTransform = clipper->transform(); + Matrix inv; + if (node->transform && inverse(node->transform, &inv)) clipTransform = inv * clipTransform; + clipper->transform(mUseTransform * clipTransform); + } + + scene->transform(mUseTransform); return scene; } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index c70fdcfa1ac..cad07f6de67 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -118,50 +118,41 @@ struct SwShapeTask : SwTask auto strokeWidth = validStrokeWidth(); SwBBox renderRegion{}; - auto visibleFill = false; - - //This checks also for the case, if the invisible shape turned to visible by alpha. - auto prepareShape = !shapePrepared(&shape) && flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient); + auto updateShape = flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform | RenderUpdateFlag::Clip); + auto updateFill = false; //Shape - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Transform) || prepareShape) { + if (updateShape || flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient)) { uint8_t alpha = 0; rshape->fillColor(nullptr, nullptr, nullptr, &alpha); - alpha = MULTIPLY(alpha, opacity); - visibleFill = (alpha > 0 || rshape->fill); - shapeReset(&shape); - if (visibleFill || clipper) { - if (!shapePrepare(&shape, rshape, transform, bbox, renderRegion, mpool, tid, clips.count > 0 ? true : false)) { - visibleFill = false; + updateFill = (MULTIPLY(alpha, opacity) || rshape->fill); + if (updateShape) shapeReset(&shape); + if (updateFill || clipper) { + if (shapePrepare(&shape, rshape, transform, bbox, renderRegion, mpool, tid, clips.count > 0 ? true : false)) { + if (!shapeGenRle(&shape, rshape, antialiasing(strokeWidth))) goto err; + } else { + updateFill = false; renderRegion.reset(); } } } //Fill - if (flags & (RenderUpdateFlag::Path |RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) { - if (visibleFill || clipper) { - if (!shapeGenRle(&shape, rshape, antialiasing(strokeWidth))) goto err; - } + if (updateFill) { if (auto fill = rshape->fill) { auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false; if (ctable) shapeResetFill(&shape); if (!shapeGenFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err; - } else { - shapeDelFill(&shape); } } //Stroke - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) { + if (updateShape || flags & RenderUpdateFlag::Stroke) { if (strokeWidth > 0.0f) { shapeResetStroke(&shape, rshape, transform); - if (!shapeGenStrokeRle(&shape, rshape, transform, bbox, renderRegion, mpool, tid)) goto err; if (auto fill = rshape->strokeFill()) { auto ctable = (flags & RenderUpdateFlag::GradientStroke) ? true : false; if (ctable) shapeResetStrokeFill(&shape); if (!shapeGenStrokeFillColors(&shape, fill, transform, surface, opacity, ctable)) goto err; - } else { - shapeDelStrokeFill(&shape); } } else { shapeDelStroke(&shape); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp index 8290927aa6e..1c139d9e753 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp @@ -1025,7 +1025,7 @@ void rleFree(SwRle* rle) bool rleClip(SwRle *rle, const SwRle *clip) { if (rle->size == 0 || clip->size == 0) return false; - auto spanCnt = rle->size > clip->size ? rle->size : clip->size; + auto spanCnt = 2 * (rle->size > clip->size ? rle->size : clip->size); //factor 2 added for safety (no real cases observed where the factor exceeded 1.4) auto spans = static_cast(malloc(sizeof(SwSpan) * (spanCnt))); auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt); diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index e00c2c1954e..2c05f5b9f48 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/thirdparty/thorvg/src/renderer/tvgPaint.cpp @@ -276,16 +276,19 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Arrayclipper) { - P(this->clipper)->ctxFlag &= ~ContextFlag::FastTrack; //reset + auto pclip = P(this->clipper); + if (pclip->renderFlag | static_cast(this->clipper)->pImpl->rFlag) renderFlag |= RenderUpdateFlag::Clip; + pclip->ctxFlag &= ~ContextFlag::FastTrack; //reset viewport = renderer->viewport(); /* TODO: Intersect the clipper's clipper, if both are FastTrack. Update the subsequent clipper first and check its ctxFlag. */ - if (!P(this->clipper)->clipper && (compFastTrack = _compFastTrack(renderer, this->clipper, pm, viewport)) == Result::Success) { - P(this->clipper)->ctxFlag |= ContextFlag::FastTrack; - } - if (compFastTrack == Result::InsufficientCondition) { - trd = P(this->clipper)->update(renderer, pm, clips, 255, pFlag, true); + if (!pclip->clipper && _compFastTrack(renderer, this->clipper, pm, viewport) == Result::Success) { + pclip->ctxFlag |= ContextFlag::FastTrack; + compFastTrack = Result::Success; + } else { + trd = pclip->update(renderer, pm, clips, 255, pFlag, true); clips.push(trd); + compFastTrack = Result::InsufficientCondition; } } diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.h b/thirdparty/thorvg/src/renderer/tvgPaint.h index 149dc0e0b51..ee35adc4676 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.h +++ b/thirdparty/thorvg/src/renderer/tvgPaint.h @@ -72,8 +72,8 @@ namespace tvg tvg::rotate(&m, degree); } } tr; + RenderUpdateFlag renderFlag = RenderUpdateFlag::None; BlendMethod blendMethod; - uint8_t renderFlag; uint8_t ctxFlag; uint8_t opacity; uint8_t refCnt = 0; //reference count diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index ce4a1bc96f5..4e48eed52c8 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -37,9 +37,14 @@ using pixel_t = uint32_t; #define DASH_PATTERN_THRESHOLD 0.001f -enum RenderUpdateFlag : uint8_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, All = 255}; +enum RenderUpdateFlag : uint16_t {None = 0, Path = 1, Color = 2, Gradient = 4, Stroke = 8, Transform = 16, Image = 32, GradientStroke = 64, Blend = 128, Clip = 256, All = 0xffff}; enum CompositionFlag : uint8_t {Invalid = 0, Opacity = 1, Blending = 2, Masking = 4, PostProcessing = 8}; //Composition Purpose +static inline void operator|=(RenderUpdateFlag& a, const RenderUpdateFlag b) +{ + a = RenderUpdateFlag(uint16_t(a) | uint16_t(b)); +} + //TODO: Move this in public header unifying with SwCanvas::Colorspace enum ColorSpace : uint8_t { diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index a19b8d6ca62..d1932764eb2 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -33,7 +33,7 @@ struct Shape::Impl RenderShape rs; //shape data RenderData rd = nullptr; //engine data Shape* shape; - uint8_t rFlag = RenderUpdateFlag::None; + RenderUpdateFlag rFlag = RenderUpdateFlag::None; uint8_t cFlag = CompositionFlag::Invalid; uint8_t opacity; //for composition diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 593e24a61a4..a4e0b865cb5 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.15.12 +VERSION=0.15.13 # Uncomment and set a git hash to use specific commit instead of tag. #GIT_COMMIT=