فهرست منبع

thorvg: Update to 0.14.8, and workaround Bezier precision regression

Fixes #96262 by backporting https://github.com/thorvg/thorvg/pull/2702.
Rémi Verschelde 1 سال پیش
والد
کامیت
7375f9b923

+ 1 - 1
thirdparty/thorvg/inc/config.h

@@ -15,5 +15,5 @@
 // For internal debugging:
 //#define THORVG_LOG_ENABLED
 
-#define THORVG_VERSION_STRING "0.14.7"
+#define THORVG_VERSION_STRING "0.14.8"
 #endif

+ 96 - 0
thirdparty/thorvg/patches/pr2702-sw_engine-handle-small-cubics.patch

@@ -0,0 +1,96 @@
+From ac7d208ed8e4651c93ce1b2384070fccac9b6cb6 Mon Sep 17 00:00:00 2001
+From: Mira Grudzinska <[email protected]>
+Date: Sun, 1 Sep 2024 22:36:18 +0200
+Subject: [PATCH] sw_engine: handle small cubics
+
+During the stroke's outline calculation, the function
+handling small cubics set all angles to zero. Such cases
+should be ignored, as further processing caused errors -
+when the cubic was small but not zero, setting the angles
+to zero resulted in incorrect outlines.
+
+@Issue: https://github.com/godotengine/godot/issues/96262
+---
+ src/renderer/sw_engine/tvgSwCommon.h   |  3 ++-
+ src/renderer/sw_engine/tvgSwMath.cpp   | 19 ++++++++++++-------
+ src/renderer/sw_engine/tvgSwStroke.cpp | 16 +++++++++++-----
+ 3 files changed, 25 insertions(+), 13 deletions(-)
+
+diff --git a/src/renderer/sw_engine/tvgSwCommon.h b/src/renderer/sw_engine/tvgSwCommon.h
+index 893e9beca..158fe8ecd 100644
+--- a/src/renderer/sw_engine/tvgSwCommon.h
++++ b/src/renderer/sw_engine/tvgSwCommon.h
+@@ -491,7 +491,8 @@ SwFixed mathSin(SwFixed angle);
+ void mathSplitCubic(SwPoint* base);
+ SwFixed mathDiff(SwFixed angle1, SwFixed angle2);
+ SwFixed mathLength(const SwPoint& pt);
+-bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut);
++bool mathSmallCubic(const SwPoint* base);
++bool mathFlatCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut);
+ SwFixed mathMean(SwFixed angle1, SwFixed angle2);
+ SwPoint mathTransform(const Point* to, const Matrix& transform);
+ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack);
+diff --git a/src/renderer/sw_engine/tvgSwMath.cpp b/src/renderer/sw_engine/tvgSwMath.cpp
+index 1093edd62..b311be05f 100644
+--- a/src/renderer/sw_engine/tvgSwMath.cpp
++++ b/src/renderer/sw_engine/tvgSwMath.cpp
+@@ -44,7 +44,17 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2)
+ }
+ 
+ 
+-bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut)
++bool mathSmallCubic(const SwPoint* base)
++{
++    auto d1 = base[2] - base[3];
++    auto d2 = base[1] - base[2];
++    auto d3 = base[0] - base[1];
++
++    return d1.small() && d2.small() && d3.small();
++}
++
++
++bool mathFlatCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut)
+ {
+     auto d1 = base[2] - base[3];
+     auto d2 = base[1] - base[2];
+@@ -52,12 +62,7 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw
+ 
+     if (d1.small()) {
+         if (d2.small()) {
+-            if (d3.small()) {
+-                angleIn = angleMid = angleOut = 0;
+-                return true;
+-            } else {
+-                angleIn = angleMid = angleOut = mathAtan(d3);
+-            }
++            angleIn = angleMid = angleOut = mathAtan(d3);
+         } else {
+             if (d3.small()) {
+                 angleIn = angleMid = angleOut = mathAtan(d2);
+diff --git a/src/renderer/sw_engine/tvgSwStroke.cpp b/src/renderer/sw_engine/tvgSwStroke.cpp
+index 575d12951..4679b72cc 100644
+--- a/src/renderer/sw_engine/tvgSwStroke.cpp
++++ b/src/renderer/sw_engine/tvgSwStroke.cpp
+@@ -441,11 +441,17 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl
+         //initialize with current direction
+         angleIn = angleOut = angleMid = stroke.angleIn;
+ 
+-        if (arc < limit && !mathSmallCubic(arc, angleIn, angleMid, angleOut)) {
+-            if (stroke.firstPt) stroke.angleIn = angleIn;
+-            mathSplitCubic(arc);
+-            arc += 3;
+-            continue;
++        if (arc < limit) {
++            if (mathSmallCubic(arc)) {
++                arc -= 3;
++                continue;
++            }
++            if (!mathFlatCubic(arc, angleIn, angleMid, angleOut)) {
++                if (stroke.firstPt) stroke.angleIn = angleIn;
++                mathSplitCubic(arc);
++                arc += 3;
++                continue;
++            }
+         }
+ 
+         if (firstArc) {

+ 8 - 0
thirdparty/thorvg/src/common/tvgMath.cpp

@@ -133,3 +133,11 @@ Point operator*(const Point& pt, const Matrix& m)
     auto ty = pt.x * m.e21 + pt.y * m.e22 + m.e23;
     return {tx, ty};
 }
+
+uint8_t mathLerp(const uint8_t &start, const uint8_t &end, float t)
+{
+    auto result = static_cast<int>(start + (end - start) * t);
+    if (result > 255) result = 255;
+    else if (result < 0) result = 0;
+    return static_cast<uint8_t>(result);
+}

+ 1 - 0
thirdparty/thorvg/src/common/tvgMath.h

@@ -259,5 +259,6 @@ static inline T mathLerp(const T &start, const T &end, float t)
     return static_cast<T>(start + (end - start) * t);
 }
 
+uint8_t mathLerp(const uint8_t &start, const uint8_t &end, float t);
 
 #endif //_TVG_MATH_H_

+ 5 - 1
thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp

@@ -588,6 +588,11 @@ static bool _hslToRgb(float hue, float saturation, float brightness, uint8_t* re
     float _red = 0, _green = 0, _blue = 0;
     uint32_t i = 0;
 
+    while (hue < 0) hue += 360.0f;
+    hue = fmod(hue, 360.0f);
+    saturation = saturation > 0 ? std::min(saturation, 1.0f) : 0.0f;
+    brightness = brightness > 0 ? std::min(brightness, 1.0f) : 0.0f;
+
     if (mathZero(saturation))  _red = _green = _blue = brightness;
     else {
         if (mathEqual(hue, 360.0)) hue = 0.0f;
@@ -714,7 +719,6 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
         const char* hue = nullptr;
         if (_parseNumber(&content, &hue, &th) && hue) {
             const char* saturation = nullptr;
-            th = float(uint32_t(th) % 360);
             hue = _skipSpace(hue, nullptr);
             hue = (char*)_skipComma(hue);
             hue = _skipSpace(hue, nullptr);

+ 8 - 4
thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h

@@ -367,7 +367,7 @@ static inline uint32_t opBlendSrcOver(uint32_t s, TVG_UNUSED uint32_t d, TVG_UNU
 }
 
 //TODO: BlendMethod could remove the alpha parameter.
-static inline uint32_t opBlendDifference(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
+static inline uint32_t opBlendDifference(uint32_t s, uint32_t d, uint8_t a)
 {
     //if (s > d) => s - d
     //else => d - s
@@ -404,8 +404,7 @@ static inline uint32_t opBlendScreen(uint32_t s, uint32_t d, TVG_UNUSED uint8_t
     return JOIN(255, c1, c2, c3);
 }
 
-
-static inline uint32_t opBlendMultiply(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
+static inline uint32_t opBlendDirectMultiply(uint32_t s, uint32_t d, uint8_t a)
 {
     // s * d
     auto c1 = MULTIPLY(C1(s), C1(d));
@@ -414,6 +413,10 @@ static inline uint32_t opBlendMultiply(uint32_t s, uint32_t d, TVG_UNUSED uint8_
     return JOIN(255, c1, c2, c3);
 }
 
+static inline uint32_t opBlendMultiply(uint32_t s, uint32_t d, uint8_t a)
+{
+    return opBlendDirectMultiply(s, d, a) + ALPHA_BLEND(d, IA(s));
+}
 
 static inline uint32_t opBlendOverlay(uint32_t s, uint32_t d, TVG_UNUSED uint8_t a)
 {
@@ -492,7 +495,8 @@ SwFixed mathSin(SwFixed angle);
 void mathSplitCubic(SwPoint* base);
 SwFixed mathDiff(SwFixed angle1, SwFixed angle2);
 SwFixed mathLength(const SwPoint& pt);
-bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut);
+bool mathSmallCubic(const SwPoint* base);
+bool mathFlatCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut);
 SwFixed mathMean(SwFixed angle1, SwFixed angle2);
 SwPoint mathTransform(const Point* to, const Matrix& transform);
 bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion, bool fastTrack);

+ 12 - 7
thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp

@@ -44,7 +44,17 @@ SwFixed mathMean(SwFixed angle1, SwFixed angle2)
 }
 
 
-bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut)
+bool mathSmallCubic(const SwPoint* base)
+{
+    auto d1 = base[2] - base[3];
+    auto d2 = base[1] - base[2];
+    auto d3 = base[0] - base[1];
+
+    return d1.small() && d2.small() && d3.small();
+}
+
+
+bool mathFlatCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed& angleOut)
 {
     auto d1 = base[2] - base[3];
     auto d2 = base[1] - base[2];
@@ -52,12 +62,7 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw
 
     if (d1.small()) {
         if (d2.small()) {
-            if (d3.small()) {
-                angleIn = angleMid = angleOut = 0;
-                return true;
-            } else {
-                angleIn = angleMid = angleOut = mathAtan(d3);
-            }
+            angleIn = angleMid = angleOut = mathAtan(d3);
         } else {
             if (d3.small()) {
                 angleIn = angleMid = angleOut = mathAtan(d2);

+ 1 - 1
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp

@@ -1383,7 +1383,7 @@ static bool _rasterDirectBlendingImage(SwSurface* surface, const SwImage* image,
                 *dst = INTERPOLATE(tmp, *dst, A(*src));
             }
         } else {
-            for (auto x = region.min.x; x < region.max.x; ++x, ++dst, ++src) {
+            for (auto x = region.min.x; x < region.max.x; x++, dst++, src++) {
                 auto tmp = ALPHA_BLEND(*src, opacity);
                 auto tmp2 = surface->blender(tmp, *dst, 255);
                 *dst = INTERPOLATE(tmp2, *dst, A(tmp));

+ 2 - 3
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp

@@ -100,7 +100,6 @@ struct SwShapeTask : SwTask
         return (width * sqrt(transform.e11 * transform.e11 + transform.e12 * transform.e12));
     }
 
-
     bool clip(SwRleData* target) override
     {
         if (shape.fastTrack) rleClipRect(target, &bbox);
@@ -447,7 +446,7 @@ bool SwRenderer::renderShape(RenderData data)
 }
 
 
-bool SwRenderer::blend(BlendMethod method)
+bool SwRenderer::blend(BlendMethod method, bool direct)
 {
     if (surface->blendMethod == method) return true;
     surface->blendMethod = method;
@@ -460,7 +459,7 @@ bool SwRenderer::blend(BlendMethod method)
             surface->blender = opBlendScreen;
             break;
         case BlendMethod::Multiply:
-            surface->blender = opBlendMultiply;
+            surface->blender = direct ? opBlendDirectMultiply : opBlendMultiply;
             break;
         case BlendMethod::Overlay:
             surface->blender = opBlendOverlay;

+ 1 - 1
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.h

@@ -46,7 +46,7 @@ public:
     RenderRegion region(RenderData data) override;
     RenderRegion viewport() override;
     bool viewport(const RenderRegion& vp) override;
-    bool blend(BlendMethod method) override;
+    bool blend(BlendMethod method, bool direct) override;
     ColorSpace colorSpace() override;
     const Surface* mainSurface() override;
 

+ 11 - 5
thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp

@@ -441,11 +441,17 @@ static void _cubicTo(SwStroke& stroke, const SwPoint& ctrl1, const SwPoint& ctrl
         //initialize with current direction
         angleIn = angleOut = angleMid = stroke.angleIn;
 
-        if (arc < limit && !mathSmallCubic(arc, angleIn, angleMid, angleOut)) {
-            if (stroke.firstPt) stroke.angleIn = angleIn;
-            mathSplitCubic(arc);
-            arc += 3;
-            continue;
+        if (arc < limit) {
+            if (mathSmallCubic(arc)) {
+                arc -= 3;
+                continue;
+            }
+            if (!mathFlatCubic(arc, angleIn, angleMid, angleOut)) {
+                if (stroke.firstPt) stroke.angleIn = angleIn;
+                mathSplitCubic(arc);
+                arc += 3;
+                continue;
+            }
         }
 
         if (firstArc) {

+ 2 - 1
thirdparty/thorvg/src/renderer/tvgLoadModule.h

@@ -101,7 +101,8 @@ struct FontLoader : LoadModule
 
     FontLoader(FileType type) : LoadModule(type) {}
 
-    virtual bool request(Shape* shape, char* text, bool italic = false) = 0;
+    virtual bool request(Shape* shape, char* text) = 0;
+    virtual bool transform(Paint* paint, float fontSize, bool italic) = 0;
 };
 
 #endif //_TVG_LOAD_MODULE_H_

+ 0 - 2
thirdparty/thorvg/src/renderer/tvgPaint.cpp

@@ -225,8 +225,6 @@ bool Paint::Impl::render(RenderMethod* renderer)
 
     if (cmp) renderer->beginComposite(cmp, compData->method, compData->target->pImpl->opacity);
 
-    renderer->blend(blendMethod);
-
     bool ret;
     PAINT_METHOD(ret, render(renderer));
 

+ 2 - 0
thirdparty/thorvg/src/renderer/tvgPicture.cpp

@@ -73,6 +73,8 @@ bool Picture::Impl::needComposition(uint8_t opacity)
 bool Picture::Impl::render(RenderMethod* renderer)
 {
     bool ret = false;
+    renderer->blend(picture->blend(), true);
+
     if (surface) return renderer->renderImage(rd);
     else if (paint) {
         Compositor* cmp = nullptr;

+ 1 - 1
thirdparty/thorvg/src/renderer/tvgRender.h

@@ -296,7 +296,7 @@ public:
     virtual RenderRegion region(RenderData data) = 0;
     virtual RenderRegion viewport() = 0;
     virtual bool viewport(const RenderRegion& vp) = 0;
-    virtual bool blend(BlendMethod method) = 0;
+    virtual bool blend(BlendMethod method, bool direct = false) = 0;
     virtual ColorSpace colorSpace() = 0;
     virtual const Surface* mainSurface() = 0;
 

+ 2 - 0
thirdparty/thorvg/src/renderer/tvgScene.h

@@ -120,6 +120,8 @@ struct Scene::Impl
         Compositor* cmp = nullptr;
         auto ret = true;
 
+        renderer->blend(scene->blend());
+
         if (needComp) {
             cmp = renderer->target(bounds(renderer), renderer->colorSpace());
             renderer->beginComposite(cmp, CompositeMethod::None, opacity);

+ 3 - 0
thirdparty/thorvg/src/renderer/tvgShape.h

@@ -54,10 +54,13 @@ struct Shape::Impl
         Compositor* cmp = nullptr;
         bool ret;
 
+        renderer->blend(shape->blend(), !needComp);
+
         if (needComp) {
             cmp = renderer->target(bounds(renderer), renderer->colorSpace());
             renderer->beginComposite(cmp, CompositeMethod::None, opacity);
         }
+
         ret = renderer->renderShape(rd);
         if (cmp) renderer->endComposite(cmp);
         return ret;

+ 9 - 10
thirdparty/thorvg/src/renderer/tvgText.h

@@ -26,12 +26,7 @@
 #include <cstring>
 #include "tvgShape.h"
 #include "tvgFill.h"
-
-#ifdef THORVG_TTF_LOADER_SUPPORT
-    #include "tvgTtfLoader.h"
-#else
-    #include "tvgLoader.h"
-#endif
+#include "tvgLoader.h"
 
 struct Text::Impl
 {
@@ -69,6 +64,11 @@ struct Text::Impl
         auto loader = LoaderMgr::loader(name);
         if (!loader) return Result::InsufficientCondition;
 
+        if (style && strstr(style, "italic")) italic = true;
+        else italic = false;
+
+        fontSize = size;
+
         //Same resource has been loaded.
         if (this->loader == loader) {
             this->loader->sharing--;  //make it sure the reference counting.
@@ -78,8 +78,6 @@ struct Text::Impl
         }
         this->loader = static_cast<FontLoader*>(loader);
 
-        fontSize = size;
-        if (style && strstr(style, "italic")) italic = true;
         changed = true;
         return Result::Success;
     }
@@ -91,6 +89,7 @@ struct Text::Impl
 
     bool render(RenderMethod* renderer)
     {
+        renderer->blend(paint->blend(), true);
         return PP(shape)->render(renderer);
     }
 
@@ -98,13 +97,13 @@ struct Text::Impl
     {
         if (!loader) return false;
 
+        loader->request(shape, utf8);
         //reload
         if (changed) {
-            loader->request(shape, utf8, italic);
             loader->read();
             changed = false;
         }
-        return loader->resize(shape, fontSize, fontSize);
+        return loader->transform(shape, fontSize, italic);
     }
 
     RenderData update(RenderMethod* renderer, const Matrix& transform, Array<RenderData>& clips, uint8_t opacity, RenderUpdateFlag pFlag, TVG_UNUSED bool clipper)

+ 12 - 6
thirdparty/thorvg/update-thorvg.sh

@@ -1,16 +1,22 @@
 #!/bin/bash -e
 
-VERSION=0.14.7
+VERSION=0.14.8
+# Uncomment and set a git hash to use specific commit instead of tag.
+#GIT_COMMIT=
 
-cd thirdparty/thorvg/ || true
+pushd "$(dirname "$0")"
 rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
 
 mkdir tmp/ && pushd tmp/
 
 # Release
-curl -L -O https://github.com/thorvg/thorvg/archive/v$VERSION.tar.gz
-# Current Github main branch tip
-#curl -L -O https://github.com/thorvg/thorvg/archive/refs/heads/main.tar.gz
+if [ ! -z "$GIT_COMMIT" ]; then
+    echo "Updating ThorVG to commit:" $GIT_COMMIT
+    curl -L -O https://github.com/thorvg/thorvg/archive/$GIT_COMMIT.tar.gz
+else
+    echo "Updating ThorVG to tagged release:" $VERSION
+    curl -L -O https://github.com/thorvg/thorvg/archive/v$VERSION.tar.gz
+fi
 
 tar --strip-components=1 -xvf *.tar.gz
 rm *.tar.gz
@@ -70,4 +76,4 @@ cp -rv src/loaders/jpg ../src/loaders/
 
 popd
 rm -rf tmp
-
+popd