Przeglądaj źródła

Merge pull request #94103 from akien-mga/thorvg-0.14.1

thorvg: Update to 0.14.1
Rémi Verschelde 1 rok temu
rodzic
commit
60da1ccd79

+ 1 - 1
thirdparty/README.md

@@ -882,7 +882,7 @@ instead of `miniz.h` as an external dependency.
 ## thorvg
 ## thorvg
 
 
 - Upstream: https://github.com/thorvg/thorvg
 - Upstream: https://github.com/thorvg/thorvg
-- Version: 0.14.0 (ae4e9d003c93325f1eba64319fa9852a0d764b4c, 2024)
+- Version: 0.14.1 (70b2f2dad158316dd08166d613b425248b36fd27, 2024)
 - License: MIT
 - License: MIT
 
 
 Files extracted from upstream source:
 Files extracted from upstream source:

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

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

+ 2 - 0
thirdparty/thorvg/inc/thorvg.h

@@ -631,6 +631,8 @@ public:
      * The Canvas rendering can be performed asynchronously. To make sure that rendering is finished,
      * The Canvas rendering can be performed asynchronously. To make sure that rendering is finished,
      * the sync() must be called after the draw() regardless of threading.
      * the sync() must be called after the draw() regardless of threading.
      *
      *
+     * @retval Result::InsufficientCondition: The canvas is either already in sync condition or in a damaged condition (a draw is required before syncing).
+     *
      * @see Canvas::draw()
      * @see Canvas::draw()
      */
      */
     virtual Result sync() noexcept;
     virtual Result sync() noexcept;

+ 1 - 0
thirdparty/thorvg/src/renderer/sw_engine/tvgSwCommon.h

@@ -23,6 +23,7 @@
 #ifndef _TVG_SW_COMMON_H_
 #ifndef _TVG_SW_COMMON_H_
 #define _TVG_SW_COMMON_H_
 #define _TVG_SW_COMMON_H_
 
 
+#include <algorithm>
 #include "tvgCommon.h"
 #include "tvgCommon.h"
 #include "tvgRender.h"
 #include "tvgRender.h"
 
 

+ 76 - 2
thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp

@@ -63,6 +63,66 @@ static void _calculateCoefficients(const SwFill* fill, uint32_t x, uint32_t y, f
 }
 }
 
 
 
 
+static uint32_t _estimateAAMargin(const Fill* fdata)
+{
+    constexpr float marginScalingFactor = 800.0f;
+    if (fdata->identifier() == TVG_CLASS_ID_RADIAL) {
+        auto radius = P(static_cast<const RadialGradient*>(fdata))->r;
+        return mathZero(radius) ? 0 : static_cast<uint32_t>(marginScalingFactor / radius);
+    }
+    auto grad = P(static_cast<const LinearGradient*>(fdata));
+    Point p1 {grad->x1, grad->y1};
+    Point p2 {grad->x2, grad->y2};
+    auto length = mathLength(&p1, &p2);
+    return mathZero(length) ? 0 : static_cast<uint32_t>(marginScalingFactor / length);
+}
+
+
+static void _adjustAAMargin(uint32_t& iMargin, uint32_t index)
+{
+    constexpr float threshold = 0.1f;
+    constexpr uint32_t iMarginMax = 40;
+
+    auto iThreshold = static_cast<uint32_t>(index * threshold);
+    if (iMargin > iThreshold) iMargin = iThreshold;
+    if (iMargin > iMarginMax) iMargin = iMarginMax;
+}
+
+
+static inline uint32_t _alphaUnblend(uint32_t c)
+{
+    auto a = (c >> 24);
+    if (a == 255 || a == 0) return c;
+    auto invA = 255.0f / static_cast<float>(a);
+    auto c0 = static_cast<uint8_t>(static_cast<float>((c >> 16) & 0xFF) * invA);
+    auto c1 = static_cast<uint8_t>(static_cast<float>((c >> 8) & 0xFF) * invA);
+    auto c2 = static_cast<uint8_t>(static_cast<float>(c & 0xFF) * invA);
+
+    return (a << 24) | (c0 << 16) | (c1 << 8) | c2;
+}
+
+
+static void _applyAA(const SwFill* fill, uint32_t begin, uint32_t end)
+{
+    if (begin == 0 || end == 0) return;
+
+    auto i = GRADIENT_STOP_SIZE - end;
+    auto rgbaEnd = _alphaUnblend(fill->ctable[i]);
+    auto rgbaBegin = _alphaUnblend(fill->ctable[begin]);
+
+    auto dt = 1.0f / (begin + end + 1.0f);
+    float t = dt;
+    while (i != begin) {
+        auto dist = 255 - static_cast<int32_t>(255 * t);
+        auto color = INTERPOLATE(rgbaEnd, rgbaBegin, dist);
+        fill->ctable[i++] = ALPHA_BLEND((color | 0xff000000), (color >> 24));
+
+        if (i == GRADIENT_STOP_SIZE) i = 0;
+        t += dt;
+    }
+}
+
+
 static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* surface, uint8_t opacity)
 static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface* surface, uint8_t opacity)
 {
 {
     if (!fill->ctable) {
     if (!fill->ctable) {
@@ -88,6 +148,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface*
     auto pos = 1.5f * inc;
     auto pos = 1.5f * inc;
     uint32_t i = 0;
     uint32_t i = 0;
 
 
+    //If repeat is true, anti-aliasing must be applied between the last and the first colors.
+    auto repeat = fill->spread == FillSpread::Repeat;
+    uint32_t iAABegin = repeat ? _estimateAAMargin(fdata) : 0;
+    uint32_t iAAEnd = 0;
+
     fill->ctable[i++] = ALPHA_BLEND(rgba | 0xff000000, a);
     fill->ctable[i++] = ALPHA_BLEND(rgba | 0xff000000, a);
 
 
     while (pos <= pColors->offset) {
     while (pos <= pColors->offset) {
@@ -97,6 +162,11 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface*
     }
     }
 
 
     for (uint32_t j = 0; j < cnt - 1; ++j) {
     for (uint32_t j = 0; j < cnt - 1; ++j) {
+        if (repeat && j == cnt - 2 && iAAEnd == 0) {
+            iAAEnd = iAABegin;
+            _adjustAAMargin(iAAEnd, GRADIENT_STOP_SIZE - i);
+        }
+
         auto curr = colors + j;
         auto curr = colors + j;
         auto next = curr + 1;
         auto next = curr + 1;
         auto delta = 1.0f / (next->offset - curr->offset);
         auto delta = 1.0f / (next->offset - curr->offset);
@@ -118,14 +188,18 @@ static bool _updateColorTable(SwFill* fill, const Fill* fdata, const SwSurface*
         }
         }
         rgba = rgba2;
         rgba = rgba2;
         a = a2;
         a = a2;
+
+        if (repeat && j == 0) _adjustAAMargin(iAABegin, i - 1);
     }
     }
     rgba = ALPHA_BLEND((rgba | 0xff000000), a);
     rgba = ALPHA_BLEND((rgba | 0xff000000), a);
 
 
     for (; i < GRADIENT_STOP_SIZE; ++i)
     for (; i < GRADIENT_STOP_SIZE; ++i)
         fill->ctable[i] = rgba;
         fill->ctable[i] = rgba;
 
 
-    //Make sure the last color stop is represented at the end of the table
-    fill->ctable[GRADIENT_STOP_SIZE - 1] = rgba;
+    //For repeat fill spread apply anti-aliasing between the last and first colors,
+    //othewise make sure the last color stop is represented at the end of the table.
+    if (repeat) _applyAA(fill, iAABegin, iAAEnd);
+    else fill->ctable[GRADIENT_STOP_SIZE - 1] = rgba;
 
 
     return true;
     return true;
 }
 }

+ 34 - 14
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRaster.cpp

@@ -1087,6 +1087,7 @@ static bool _rasterDirectScaledMaskedImage(SwSurface* surface, const SwImage* im
 
 
 static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 {
 {
+    TVGERR("SW_ENGINE", "Not supported ScaledMaskedImage!");
 #if 0 //Enable it when GRAYSCALE image is supported
 #if 0 //Enable it when GRAYSCALE image is supported
     TVGLOG("SW_ENGINE", "Scaled Masked(%d) Image [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
     TVGLOG("SW_ENGINE", "Scaled Masked(%d) Image [Region: %lu %lu %lu %lu]", (int)surface->compositor->method, region.min.x, region.min.y, region.max.x - region.min.x, region.max.y - region.min.y);
 
 
@@ -1100,6 +1101,11 @@ static bool _rasterScaledMaskedImage(SwSurface* surface, const SwImage* image, c
 
 
 static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 {
 {
+    if (surface->channelSize == sizeof(uint8_t)) {
+        TVGERR("SW_ENGINE", "Not supported grayscale scaled matted image!");
+        return false;
+    }
+
     auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
     auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
     auto csize = surface->compositor->image.channelSize;
     auto csize = surface->compositor->image.channelSize;
     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
     auto cbuffer = surface->compositor->image.buf8 + (region.min.y * surface->compositor->image.stride + region.min.x) * csize;
@@ -1130,6 +1136,11 @@ static bool _rasterScaledMattedImage(SwSurface* surface, const SwImage* image, c
 
 
 static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 {
 {
+    if (surface->channelSize == sizeof(uint8_t)) {
+        TVGERR("SW_ENGINE", "Not supported grayscale scaled blending image!");
+        return false;
+    }
+
     auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
     auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
     auto sampleSize = _sampleSize(image->scale);
     auto sampleSize = _sampleSize(image->scale);
@@ -1152,19 +1163,33 @@ static bool _rasterScaledBlendingImage(SwSurface* surface, const SwImage* image,
 
 
 static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const Matrix* itransform, const SwBBox& region, uint8_t opacity)
 {
 {
-    auto dbuffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
     auto scaleMethod = image->scale < DOWN_SCALE_TOLERANCE ? _interpDownScaler : _interpUpScaler;
     auto sampleSize = _sampleSize(image->scale);
     auto sampleSize = _sampleSize(image->scale);
     int32_t miny = 0, maxy = 0;
     int32_t miny = 0, maxy = 0;
 
 
-    for (auto y = region.min.y; y < region.max.y; ++y, dbuffer += surface->stride) {
-        SCALED_IMAGE_RANGE_Y(y)
-        auto dst = dbuffer;
-        for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
-            SCALED_IMAGE_RANGE_X
-            auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
-            if (opacity < 255) src = ALPHA_BLEND(src, opacity);
-            *dst = src + ALPHA_BLEND(*dst, IA(src));
+    //32bits channels
+    if (surface->channelSize == sizeof(uint32_t)) {
+        auto buffer = surface->buf32 + (region.min.y * surface->stride + region.min.x);
+        for (auto y = region.min.y; y < region.max.y; ++y, buffer += surface->stride) {
+            SCALED_IMAGE_RANGE_Y(y)
+            auto dst = buffer;
+            for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
+                SCALED_IMAGE_RANGE_X
+                auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
+                if (opacity < 255) src = ALPHA_BLEND(src, opacity);
+                *dst = src + ALPHA_BLEND(*dst, IA(src));
+            }
+        }
+    } else if (surface->channelSize == sizeof(uint8_t)) {
+        auto buffer = surface->buf8 + (region.min.y * surface->stride + region.min.x);
+        for (auto y = region.min.y; y < region.max.y; ++y, buffer += surface->stride) {
+            SCALED_IMAGE_RANGE_Y(y)
+            auto dst = buffer;
+            for (auto x = region.min.x; x < region.max.x; ++x, ++dst) {
+                SCALED_IMAGE_RANGE_X
+                auto src = scaleMethod(image->buf32, image->stride, image->w, image->h, sx, sy, miny, maxy, sampleSize);
+                *dst = MULTIPLY(A(src), opacity);
+            }
         }
         }
     }
     }
     return true;
     return true;
@@ -1173,11 +1198,6 @@ static bool _rasterScaledImage(SwSurface* surface, const SwImage* image, const M
 
 
 static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
 static bool _scaledImage(SwSurface* surface, const SwImage* image, const Matrix* transform, const SwBBox& region, uint8_t opacity)
 {
 {
-    if (surface->channelSize == sizeof(uint8_t)) {
-        TVGERR("SW_ENGINE", "Not supported grayscale Textmap polygon mesh!");
-        return false;
-    }
-
     Matrix itransform;
     Matrix itransform;
 
 
     if (transform) {
     if (transform) {

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

@@ -20,6 +20,7 @@
  * SOFTWARE.
  * SOFTWARE.
  */
  */
 
 
+#include <algorithm>
 #include "tvgMath.h"
 #include "tvgMath.h"
 #include "tvgSwCommon.h"
 #include "tvgSwCommon.h"
 #include "tvgTaskScheduler.h"
 #include "tvgTaskScheduler.h"
@@ -86,7 +87,7 @@ struct SwShapeTask : SwTask
        Additionally, the stroke style should not be dashed. */
        Additionally, the stroke style should not be dashed. */
     bool antialiasing(float strokeWidth)
     bool antialiasing(float strokeWidth)
     {
     {
-        return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->strokeTrim();
+        return strokeWidth < 2.0f || rshape->stroke->dashCnt > 0 || rshape->stroke->strokeFirst || rshape->strokeTrim() || rshape->stroke->color[3] < 255;;
     }
     }
 
 
     float validStrokeWidth()
     float validStrokeWidth()

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

@@ -129,7 +129,7 @@ struct Canvas::Impl
             return Result::Success;
             return Result::Success;
         }
         }
 
 
-        return Result::InsufficientCondition;
+        return Result::Unknown;
     }
     }
 
 
     Result viewport(int32_t x, int32_t y, int32_t w, int32_t h)
     Result viewport(int32_t x, int32_t y, int32_t w, int32_t h)

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

@@ -103,7 +103,7 @@ struct RenderRegion
     void intersect(const RenderRegion& rhs);
     void intersect(const RenderRegion& rhs);
     void add(const RenderRegion& rhs);
     void add(const RenderRegion& rhs);
 
 
-    bool operator==(const RenderRegion& rhs)
+    bool operator==(const RenderRegion& rhs) const
     {
     {
         if (x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h) return true;
         if (x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h) return true;
         return false;
         return false;

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

@@ -296,6 +296,7 @@ struct Shape::Impl
         if (!rs.stroke) rs.stroke = new RenderStroke();
         if (!rs.stroke) rs.stroke = new RenderStroke();
         if (rs.stroke->fill && rs.stroke->fill != p) delete(rs.stroke->fill);
         if (rs.stroke->fill && rs.stroke->fill != p) delete(rs.stroke->fill);
         rs.stroke->fill = p;
         rs.stroke->fill = p;
+        rs.stroke->color[3] = 0;
 
 
         flag |= RenderUpdateFlag::Stroke;
         flag |= RenderUpdateFlag::Stroke;
         flag |= RenderUpdateFlag::GradientStroke;
         flag |= RenderUpdateFlag::GradientStroke;

+ 1 - 1
thirdparty/thorvg/update-thorvg.sh

@@ -1,6 +1,6 @@
 #!/bin/bash -e
 #!/bin/bash -e
 
 
-VERSION=0.14.0
+VERSION=0.14.1
 
 
 cd thirdparty/thorvg/ || true
 cd thirdparty/thorvg/ || true
 rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/
 rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/