1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

thorvg: Update to 0.15.13

This commit is contained in:
Jakub Marcowski
2025-05-28 00:43:14 +02:00
parent 99f5a3d665
commit 5c94127c2d
14 changed files with 71 additions and 69 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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);
}
}

View File

@@ -577,7 +577,7 @@ struct SvgLoaderData
SvgNode* def = nullptr; //also used to store nested graphic nodes
SvgNode* cssStyle = nullptr;
Array<SvgStyleGradient*> gradients;
SvgStyleGradient* latestGradient = nullptr; //For stops
Array<SvgStyleGradient*> gradientStack; //For stops
SvgParser* svgParse = nullptr;
Array<SvgNodeIdPair> cloneNodes;
Array<SvgNodeIdPair> nodesToStyle;

View File

@@ -752,12 +752,22 @@ static unique_ptr<Scene> _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;
}

View File

@@ -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);

View File

@@ -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<SwSpan*>(malloc(sizeof(SwSpan) * (spanCnt)));
auto spansEnd = _intersectSpansRegion(clip, rle, spans, spanCnt);

View File

@@ -276,16 +276,19 @@ RenderData Paint::Impl::update(RenderMethod* renderer, const Matrix& pm, Array<R
/* 2. Clipping */
if (this->clipper) {
P(this->clipper)->ctxFlag &= ~ContextFlag::FastTrack; //reset
auto pclip = P(this->clipper);
if (pclip->renderFlag | static_cast<Shape*>(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;
}
}

View File

@@ -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

View File

@@ -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
{

View File

@@ -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

View File

@@ -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=