Ver Fonte

Merge pull request #92915 from capnm/240608-svg-tvg0.13.7

ThorVG: Update to 0.13.7
Rémi Verschelde há 1 ano atrás
pai
commit
c568264bab

+ 1 - 1
thirdparty/README.md

@@ -882,7 +882,7 @@ instead of `miniz.h` as an external dependency.
 ## thorvg
 
 - Upstream: https://github.com/thorvg/thorvg
-- Version: 0.13.3 (6235068cad8cad176ccd0cbcf82f25e985fbc258, 2024)
+- Version: 0.13.7 (d2c0428a99f7305c086caffe0c730add601ebd6e, 2024)
 - License: MIT
 
 Files extracted from upstream source:

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

@@ -13,5 +13,5 @@
 // For internal debugging:
 //#define THORVG_LOG_ENABLED
 
-#define THORVG_VERSION_STRING "0.13.5"
+#define THORVG_VERSION_STRING "0.13.7"
 #endif

+ 36 - 12
thirdparty/thorvg/inc/thorvg.h

@@ -80,7 +80,7 @@ enum class Result
     InsufficientCondition, ///< The value returned in case the request cannot be processed - e.g. asking for properties of an object, which does not exist.
     FailedAllocation,      ///< The value returned in case of unsuccessful memory allocation.
     MemoryCorruption,      ///< The value returned in the event of bad memory handling - e.g. failing in pointer releasing or casting
-    NonSupport,            ///< The value returned in case of choosing unsupported options.
+    NonSupport,            ///< The value returned in case of choosing unsupported engine features(options).
     Unknown                ///< The value returned in all other cases.
 };
 
@@ -982,7 +982,7 @@ public:
      *
      * @param[in] width The width of the stroke. The default value is 0.
      *
-     * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
+     * @retval Result::Success when succeed.
      */
     Result stroke(float width) noexcept;
 
@@ -994,7 +994,7 @@ public:
      * @param[in] b The blue color channel value in the range [0 ~ 255]. The default value is 0.
      * @param[in] a The alpha channel value in the range [0 ~ 255], where 0 is completely transparent and 255 is opaque. The default value is 0.
      *
-     * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
+     * @retval Result::Success when succeed.
      */
     Result stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255) noexcept;
 
@@ -1004,8 +1004,7 @@ public:
      * @param[in] f The gradient fill.
      *
      * @retval Result::Success When succeed.
-     * @retval Result::FailedAllocation An internal error with a memory allocation for an object to be filled.
-     * @retval Result::MemoryCorruption In case a @c nullptr is passed as the argument.
+     * @retval Result::MemoryCorruption In case a @c nullptr is passed as the argument or an error with accessing it.
      */
     Result stroke(std::unique_ptr<Fill> f) noexcept;
 
@@ -1029,7 +1028,7 @@ public:
      *
      * @param[in] cap The cap style value. The default value is @c StrokeCap::Square.
      *
-     * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
+     * @retval Result::Success when succeed.
      */
     Result stroke(StrokeCap cap) noexcept;
 
@@ -1040,22 +1039,37 @@ public:
      *
      * @param[in] join The join style value. The default value is @c StrokeJoin::Bevel.
      *
-     * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
+     * @retval Result::Success when succeed.
      */
     Result stroke(StrokeJoin join) noexcept;
 
-
     /**
      * @brief Sets the stroke miterlimit.
      *
      * @param[in] miterlimit The miterlimit imposes a limit on the extent of the stroke join, when the @c StrokeJoin::Miter join style is set. The default value is 4.
      *
-     * @retval Result::Success when succeed, Result::NonSupport unsupported value, Result::FailedAllocation otherwise.
+     * @retval Result::Success when succeed or Result::InvalidArgument for @p miterlimit values less than zero.
      * 
      * @since 0.11
      */
     Result strokeMiterlimit(float miterlimit) noexcept;
 
+    /**
+     * @brief Sets the trim of the stroke along the defined path segment, allowing control over which part of the stroke is visible.
+     *
+     * The values of the arguments @p begin, @p end, and @p offset are in the range of 0.0 to 1.0, representing the beginning of the path and the end, respectively.
+     *
+     * @param[in] begin Specifies the start of the segment to display along the path.
+     * @param[in] end Specifies the end of the segment to display along the path.
+     * @param[in] simultaneous Determines how to trim multiple paths within a single shape. If set to @c true (default), trimming is applied simultaneously to all paths;
+     * Otherwise, all paths are treated as a single entity with a combined length equal to the sum of their individual lengths and are trimmed as such.
+     *
+     * @retval Result::Success when succeed.
+     *
+     * @note Experimental API
+     */
+    Result strokeTrim(float begin, float end, bool simultaneous = true) noexcept;
+
     /**
      * @brief Sets the solid color for all of the figures from the path.
      *
@@ -1095,19 +1109,17 @@ public:
      */
     Result fill(FillRule r) noexcept;
 
-
     /**
      * @brief Sets the rendering order of the stroke and the fill.
      *
      * @param[in] strokeFirst If @c true the stroke is rendered before the fill, otherwise the stroke is rendered as the second one (the default option).
      *
-     * @retval Result::Success when succeed, Result::FailedAllocation otherwise.
+     * @retval Result::Success when succeed.
      *
      * @since 0.10
      */
     Result order(bool strokeFirst) noexcept;
 
-
     /**
      * @brief Gets the commands data of the path.
      *
@@ -1210,6 +1222,18 @@ public:
      */
     float strokeMiterlimit() const noexcept;
 
+    /**
+     * @brief Gets the trim of the stroke along the defined path segment.
+     *
+     * @param[out] begin The starting point of the segment to display along the path.
+     * @param[out] end Specifies the end of the segment to display along the path.
+     *
+     * @retval @c true if trimming is applied simultaneously to all paths of the shape, @c false otherwise.
+     *
+     * @note Experimental API
+     */
+    bool strokeTrim(float* begin, float* end) const noexcept;
+
     /**
      * @brief Creates a new Shape object.
      *

+ 15 - 0
thirdparty/thorvg/src/common/tvgCompressor.cpp

@@ -472,4 +472,19 @@ size_t b64Decode(const char* encoded, const size_t len, char** decoded)
 }
 
 
+/************************************************************************/
+/* DJB2 Implementation                                                   */
+/************************************************************************/
+
+unsigned long djb2Encode(const char* str)
+{
+    unsigned long hash = 5381;
+    int c;
+
+    while ((c = *str++)) {
+        hash = ((hash << 5) + hash) + c; // hash * 33 + c
+    }
+    return hash;
+}
+
 }

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

@@ -30,6 +30,7 @@ namespace tvg
     uint8_t* lzwEncode(const uint8_t* uncompressed, uint32_t uncompressedSizeBytes, uint32_t* compressedSizeBytes, uint32_t* compressedSizeBits);
     uint8_t* lzwDecode(const uint8_t* compressed, uint32_t compressedSizeBytes, uint32_t compressedSizeBits, uint32_t uncompressedSizeBytes);
     size_t b64Decode(const char* encoded, const size_t len, char** decoded);
+    unsigned long djb2Encode(const char* str);
 }
 
 #endif  //_TVG_COMPRESSOR_H_

+ 37 - 26
thirdparty/thorvg/src/common/tvgMath.cpp

@@ -47,23 +47,14 @@ bool mathInverse(const Matrix* m, Matrix* out)
 }
 
 
-Matrix mathMultiply(const Matrix* lhs, const Matrix* rhs)
+bool mathIdentity(const Matrix* m)
 {
-    Matrix m;
-
-    m.e11 = lhs->e11 * rhs->e11 + lhs->e12 * rhs->e21 + lhs->e13 * rhs->e31;
-    m.e12 = lhs->e11 * rhs->e12 + lhs->e12 * rhs->e22 + lhs->e13 * rhs->e32;
-    m.e13 = lhs->e11 * rhs->e13 + lhs->e12 * rhs->e23 + lhs->e13 * rhs->e33;
-
-    m.e21 = lhs->e21 * rhs->e11 + lhs->e22 * rhs->e21 + lhs->e23 * rhs->e31;
-    m.e22 = lhs->e21 * rhs->e12 + lhs->e22 * rhs->e22 + lhs->e23 * rhs->e32;
-    m.e23 = lhs->e21 * rhs->e13 + lhs->e22 * rhs->e23 + lhs->e23 * rhs->e33;
-
-    m.e31 = lhs->e31 * rhs->e11 + lhs->e32 * rhs->e21 + lhs->e33 * rhs->e31;
-    m.e32 = lhs->e31 * rhs->e12 + lhs->e32 * rhs->e22 + lhs->e33 * rhs->e32;
-    m.e33 = lhs->e31 * rhs->e13 + lhs->e32 * rhs->e23 + lhs->e33 * rhs->e33;
-
-    return m;
+    if (m->e11 != 1.0f || m->e12 != 0.0f || m->e13 != 0.0f ||
+        m->e21 != 0.0f || m->e22 != 1.0f || m->e23 != 0.0f ||
+        m->e31 != 0.0f || m->e32 != 0.0f || m->e33 != 1.0f) {
+        return false;
+    }
+    return true;
 }
 
 
@@ -82,21 +73,41 @@ void mathRotate(Matrix* m, float degree)
 }
 
 
-bool mathIdentity(const Matrix* m)
+Matrix operator*(const Matrix& lhs, const Matrix& rhs)
 {
-    if (m->e11 != 1.0f || m->e12 != 0.0f || m->e13 != 0.0f ||
-        m->e21 != 0.0f || m->e22 != 1.0f || m->e23 != 0.0f ||
-        m->e31 != 0.0f || m->e32 != 0.0f || m->e33 != 1.0f) {
-        return false;
+    Matrix m;
+
+    m.e11 = lhs.e11 * rhs.e11 + lhs.e12 * rhs.e21 + lhs.e13 * rhs.e31;
+    m.e12 = lhs.e11 * rhs.e12 + lhs.e12 * rhs.e22 + lhs.e13 * rhs.e32;
+    m.e13 = lhs.e11 * rhs.e13 + lhs.e12 * rhs.e23 + lhs.e13 * rhs.e33;
+
+    m.e21 = lhs.e21 * rhs.e11 + lhs.e22 * rhs.e21 + lhs.e23 * rhs.e31;
+    m.e22 = lhs.e21 * rhs.e12 + lhs.e22 * rhs.e22 + lhs.e23 * rhs.e32;
+    m.e23 = lhs.e21 * rhs.e13 + lhs.e22 * rhs.e23 + lhs.e23 * rhs.e33;
+
+    m.e31 = lhs.e31 * rhs.e11 + lhs.e32 * rhs.e21 + lhs.e33 * rhs.e31;
+    m.e32 = lhs.e31 * rhs.e12 + lhs.e32 * rhs.e22 + lhs.e33 * rhs.e32;
+    m.e33 = lhs.e31 * rhs.e13 + lhs.e32 * rhs.e23 + lhs.e33 * rhs.e33;
+
+    return m;
+}
+
+
+bool operator==(const Matrix& lhs, const Matrix& rhs)
+{
+    if (!mathEqual(lhs.e11, rhs.e11) || !mathEqual(lhs.e12, rhs.e12) || !mathEqual(lhs.e13, rhs.e13) ||
+        !mathEqual(lhs.e21, rhs.e21) || !mathEqual(lhs.e22, rhs.e22) || !mathEqual(lhs.e23, rhs.e23) ||
+        !mathEqual(lhs.e31, rhs.e31) || !mathEqual(lhs.e32, rhs.e32) || !mathEqual(lhs.e33, rhs.e33)) {
+       return false;
     }
     return true;
 }
 
 
-void mathMultiply(Point* pt, const Matrix* transform)
+void operator*=(Point& pt, const Matrix& m)
 {
-    auto tx = pt->x * transform->e11 + pt->y * transform->e12 + transform->e13;
-    auto ty = pt->x * transform->e21 + pt->y * transform->e22 + transform->e23;
-    pt->x = tx;
-    pt->y = ty;
+    auto tx = pt.x * m.e11 + pt.y * m.e12 + m.e13;
+    auto ty = pt.x * m.e21 + pt.y * m.e22 + m.e23;
+    pt.x = tx;
+    pt.y = ty;
 }

+ 52 - 29
thirdparty/thorvg/src/common/tvgMath.h

@@ -38,11 +38,9 @@
 #define mathMax(x, y) (((x) > (y)) ? (x) : (y))
 
 
-bool mathInverse(const Matrix* m, Matrix* out);
-Matrix mathMultiply(const Matrix* lhs, const Matrix* rhs);
-void mathRotate(Matrix* m, float degree);
-bool mathIdentity(const Matrix* m);
-void mathMultiply(Point* pt, const Matrix* transform);
+/************************************************************************/
+/* General functions                                                    */
+/************************************************************************/
 
 
 static inline float mathDeg2Rad(float degree)
@@ -63,28 +61,21 @@ static inline bool mathZero(float a)
 }
 
 
-static inline bool mathZero(const Point& p)
-{
-    return mathZero(p.x) && mathZero(p.y);
-}
-
-
 static inline bool mathEqual(float a, float b)
 {
     return mathZero(a - b);
 }
 
 
-static inline bool mathEqual(const Matrix& a, const Matrix& b)
-{
-    if (!mathEqual(a.e11, b.e11) || !mathEqual(a.e12, b.e12) || !mathEqual(a.e13, b.e13) ||
-        !mathEqual(a.e21, b.e21) || !mathEqual(a.e22, b.e22) || !mathEqual(a.e23, b.e23) ||
-        !mathEqual(a.e31, b.e31) || !mathEqual(a.e32, b.e32) || !mathEqual(a.e33, b.e33)) {
-       return false;
-    }
-    return true;
-}
+/************************************************************************/
+/* Matrix functions                                                     */
+/************************************************************************/
 
+void mathRotate(Matrix* m, float degree);
+bool mathInverse(const Matrix* m, Matrix* out);
+bool mathIdentity(const Matrix* m);
+Matrix operator*(const Matrix& lhs, const Matrix& rhs);
+bool operator==(const Matrix& lhs, const Matrix& rhs);
 
 static inline bool mathRightAngle(const Matrix* m)
 {
@@ -114,15 +105,6 @@ static inline void mathIdentity(Matrix* m)
 }
 
 
-static inline void mathTransform(Matrix* transform, Point* coord)
-{
-    auto x = coord->x;
-    auto y = coord->y;
-    coord->x = x * transform->e11 + y * transform->e12 + transform->e13;
-    coord->y = x * transform->e21 + y * transform->e22 + transform->e23;
-}
-
-
 static inline void mathScale(Matrix* m, float sx, float sy)
 {
     m->e11 *= sx;
@@ -158,12 +140,37 @@ static inline void mathTranslateR(Matrix* m, float x, float y)
 }
 
 
+static inline bool operator!=(const Matrix& lhs, const Matrix& rhs)
+{
+    return !(lhs == rhs);
+}
+
+
+static inline void operator*=(Matrix& lhs, const Matrix& rhs)
+{
+    lhs = lhs * rhs;
+}
+
+
 static inline void mathLog(Matrix* m)
 {
     TVGLOG("MATH", "Matrix: [%f %f %f] [%f %f %f] [%f %f %f]", m->e11, m->e12, m->e13, m->e21, m->e22, m->e23, m->e31, m->e32, m->e33);
 }
 
 
+/************************************************************************/
+/* Point functions                                                      */
+/************************************************************************/
+
+void operator*=(Point& pt, const Matrix& m);
+
+
+static inline bool mathZero(const Point& p)
+{
+    return mathZero(p.x) && mathZero(p.y);
+}
+
+
 static inline float mathLength(const Point* a, const Point* b)
 {
     auto x = b->x - a->x;
@@ -182,6 +189,18 @@ static inline float mathLength(const Point& a)
 }
 
 
+static inline bool operator==(const Point& lhs, const Point& rhs)
+{
+    return mathEqual(lhs.x, rhs.x) && mathEqual(lhs.y, rhs.y);
+}
+
+
+static inline bool operator!=(const Point& lhs, const Point& rhs)
+{
+    return !(lhs == rhs);
+}
+
+
 static inline Point operator-(const Point& lhs, const Point& rhs)
 {
     return {lhs.x - rhs.x, lhs.y - rhs.y};
@@ -212,6 +231,10 @@ static inline Point operator/(const Point& lhs, const float rhs)
 }
 
 
+/************************************************************************/
+/* Interpolation functions                                              */
+/************************************************************************/
+
 template <typename T>
 static inline T mathLerp(const T &start, const T &end, float t)
 {

+ 11 - 11
thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp

@@ -709,7 +709,7 @@ static bool _toColor(const char* str, uint8_t* r, uint8_t* g, uint8_t* b, char**
         *ref = _idFromUrl((const char*)(str + 3));
         return true;
     } else if (len >= 10 && (str[0] == 'h' || str[0] == 'H') && (str[1] == 's' || str[1] == 'S') && (str[2] == 'l' || str[2] == 'L') && str[3] == '(' && str[len - 1] == ')') {
-        float th, ts, tb;
+        float_t th, ts, tb;
         const char *content, *hue, *satuation, *brightness;
         content = str + 4;
         content = _skipSpace(content, nullptr);
@@ -840,14 +840,14 @@ static Matrix* _parseTransformationMatrix(const char* value)
         if (state == MatrixState::Matrix) {
             if (ptCount != 6) goto error;
             Matrix tmp = {points[0], points[2], points[4], points[1], points[3], points[5], 0, 0, 1};
-            *matrix = mathMultiply(matrix, &tmp);
+            *matrix *= tmp;
         } else if (state == MatrixState::Translate) {
             if (ptCount == 1) {
                 Matrix tmp = {1, 0, points[0], 0, 1, 0, 0, 0, 1};
-                *matrix = mathMultiply(matrix, &tmp);
+                *matrix *= tmp;
             } else if (ptCount == 2) {
                 Matrix tmp = {1, 0, points[0], 0, 1, points[1], 0, 0, 1};
-                *matrix = mathMultiply(matrix, &tmp);
+                *matrix *= tmp;
             } else goto error;
         } else if (state == MatrixState::Rotate) {
             //Transform to signed.
@@ -857,14 +857,14 @@ static Matrix* _parseTransformationMatrix(const char* value)
             auto s = sinf(mathDeg2Rad(points[0]));
             if (ptCount == 1) {
                 Matrix tmp = { c, -s, 0, s, c, 0, 0, 0, 1 };
-                *matrix = mathMultiply(matrix, &tmp);
+                *matrix *= tmp;
             } else if (ptCount == 3) {
                 Matrix tmp = { 1, 0, points[1], 0, 1, points[2], 0, 0, 1 };
-                *matrix = mathMultiply(matrix, &tmp);
+                *matrix *= tmp;
                 tmp = { c, -s, 0, s, c, 0, 0, 0, 1 };
-                *matrix = mathMultiply(matrix, &tmp);
+                *matrix *= tmp;
                 tmp = { 1, 0, -points[1], 0, 1, -points[2], 0, 0, 1 };
-                *matrix = mathMultiply(matrix, &tmp);
+                *matrix *= tmp;
             } else {
                 goto error;
             }
@@ -874,17 +874,17 @@ static Matrix* _parseTransformationMatrix(const char* value)
             auto sy = sx;
             if (ptCount == 2) sy = points[1];
             Matrix tmp = { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
-            *matrix = mathMultiply(matrix, &tmp);
+            *matrix *= tmp;
         } else if (state == MatrixState::SkewX) {
             if (ptCount != 1) goto error;
             auto deg = tanf(mathDeg2Rad(points[0]));
             Matrix tmp = { 1, deg, 0, 0, 1, 0, 0, 0, 1 };
-            *matrix = mathMultiply(matrix, &tmp);
+            *matrix *= tmp;
         } else if (state == MatrixState::SkewY) {
             if (ptCount != 1) goto error;
             auto deg = tanf(mathDeg2Rad(points[0]));
             Matrix tmp = { 1, 0, 0, deg, 1, 0, 0, 0, 1 };
-            *matrix = mathMultiply(matrix, &tmp);
+            *matrix *= tmp;
         }
     }
     return matrix;

+ 14 - 10
thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp

@@ -203,9 +203,9 @@ static bool _appendClipUseNode(SvgLoaderData& loaderData, SvgNode* node, Shape*
     if (node->transform) finalTransform = *node->transform;
     if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) {
         Matrix m = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1};
-        finalTransform = mathMultiply(&finalTransform, &m);
+        finalTransform *= m;
     }
-    if (child->transform) finalTransform = mathMultiply(child->transform, &finalTransform);
+    if (child->transform) finalTransform = *child->transform * finalTransform;
 
     return _appendClipShape(loaderData, child, shape, vBox, svgPath, mathIdentity((const Matrix*)(&finalTransform)) ? nullptr : &finalTransform);
 }
@@ -228,13 +228,13 @@ static Matrix _compositionTransform(Paint* paint, const SvgNode* node, const Svg
         m = *node->transform;
     }
     if (compNode->transform) {
-        m = mathMultiply(&m, compNode->transform);
+        m *= *compNode->transform;
     }
     if (!compNode->node.clip.userSpace) {
         float x, y, w, h;
         P(paint)->bounds(&x, &y, &w, &h, false, false);
         Matrix mBBox = {w, 0, x, 0, h, y, 0, 0, 1};
-        m = mathMultiply(&m, &mBBox);
+        m *= mBBox;
     }
     return m;
 }
@@ -474,7 +474,10 @@ static bool _appendClipShape(SvgLoaderData& loaderData, SvgNode* node, Shape* sh
         auto ptsCnt = shape->pathCoords(&pts);
 
         auto p = const_cast<Point*>(pts) + currentPtsCnt;
-        while (currentPtsCnt++ < ptsCnt) mathMultiply(p++, m);
+        while (currentPtsCnt++ < ptsCnt) {
+            *p *= *m;
+            ++p;
+        }
     }
 
     _applyProperty(loaderData, node, shape, vBox, svgPath, true);
@@ -505,6 +508,7 @@ static constexpr struct
 } imageMimeTypes[] = {
     {"jpeg", sizeof("jpeg"), imageMimeTypeEncoding::base64},
     {"png", sizeof("png"), imageMimeTypeEncoding::base64},
+    {"webp", sizeof("webp"), imageMimeTypeEncoding::base64},
     {"svg+xml", sizeof("svg+xml"), imageMimeTypeEncoding::base64 | imageMimeTypeEncoding::utf8},
 };
 
@@ -615,7 +619,7 @@ static unique_ptr<Picture> _imageBuildHelper(SvgLoaderData& loaderData, SvgNode*
         auto sy = node->node.image.h / h;
         m = {sx, 0, node->node.image.x, 0, sy, node->node.image.y, 0, 0, 1};
     }
-    if (node->transform) m = mathMultiply(node->transform, &m);
+    if (node->transform) m = *node->transform * m;
     picture->transform(m);
 
     _applyComposition(loaderData, picture.get(), node, vBox, svgPath);
@@ -708,7 +712,7 @@ static unique_ptr<Scene> _useBuildHelper(SvgLoaderData& loaderData, const SvgNod
     if (node->transform) mUseTransform = *node->transform;
     if (node->node.use.x != 0.0f || node->node.use.y != 0.0f) {
         Matrix mTranslate = {1, 0, node->node.use.x, 0, 1, node->node.use.y, 0, 0, 1};
-        mUseTransform = mathMultiply(&mUseTransform, &mTranslate);
+        mUseTransform *= mTranslate;
     }
 
     if (node->node.use.symbol) {
@@ -732,9 +736,9 @@ static unique_ptr<Scene> _useBuildHelper(SvgLoaderData& loaderData, const SvgNod
         // mSceneTransform = mUseTransform * mSymbolTransform * mViewBox
         Matrix mSceneTransform = mViewBox;
         if (node->node.use.symbol->transform) {
-            mSceneTransform = mathMultiply(node->node.use.symbol->transform, &mViewBox);
+            mSceneTransform = *node->node.use.symbol->transform * mViewBox;
         }
-        mSceneTransform = mathMultiply(&mUseTransform, &mSceneTransform);
+        mSceneTransform = mUseTransform * mSceneTransform;
         scene->transform(mSceneTransform);
 
         if (node->node.use.symbol->node.symbol.overflowVisible) {
@@ -746,7 +750,7 @@ static unique_ptr<Scene> _useBuildHelper(SvgLoaderData& loaderData, const SvgNod
             // mClipTransform = mUseTransform * mSymbolTransform
             Matrix mClipTransform = mUseTransform;
             if (node->node.use.symbol->transform) {
-                mClipTransform = mathMultiply(&mUseTransform, node->node.use.symbol->transform);
+                mClipTransform = mUseTransform * *node->node.use.symbol->transform;
             }
             viewBoxClip->transform(mClipTransform);
 

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

@@ -150,7 +150,7 @@ bool _prepareLinear(SwFill* fill, const LinearGradient* linear, const Matrix* tr
     bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform));
 
     if (isTransformation) {
-        if (transform) gradTransform = mathMultiply(transform, &gradTransform);
+        if (transform) gradTransform = *transform * gradTransform;
     } else if (transform) {
         gradTransform = *transform;
         isTransformation = true;
@@ -216,7 +216,7 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr
     bool isTransformation = !mathIdentity((const Matrix*)(&gradTransform));
 
     if (transform) {
-        if (isTransformation) gradTransform = mathMultiply(transform, &gradTransform);
+        if (isTransformation) gradTransform = *transform * gradTransform;
         else {
             gradTransform = *transform;
             isTransformation = true;

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

@@ -81,7 +81,7 @@ SwMpool* mpoolInit(uint32_t threads)
 {
     auto allocSize = threads + 1;
 
-    auto mpool = static_cast<SwMpool*>(calloc(sizeof(SwMpool), 1));
+    auto mpool = static_cast<SwMpool*>(calloc(1, sizeof(SwMpool)));
     mpool->outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * allocSize));
     mpool->strokeOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * allocSize));
     mpool->dashOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * allocSize));

+ 4 - 4
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h

@@ -1108,7 +1108,7 @@ static bool _rasterTexmapPolygon(SwSurface* surface, const SwImage* image, const
 
     float ys = FLT_MAX, ye = -1.0f;
     for (int i = 0; i < 4; i++) {
-        if (transform) mathMultiply(&vertices[i].pt, transform);
+        if (transform) vertices[i].pt *= *transform;
         if (vertices[i].pt.y < ys) ys = vertices[i].pt.y;
         if (vertices[i].pt.y > ye) ye = vertices[i].pt.y;
     }
@@ -1169,9 +1169,9 @@ static bool _rasterTexmapPolygonMesh(SwSurface* surface, const SwImage* image, c
     float ys = FLT_MAX, ye = -1.0f;
     for (uint32_t i = 0; i < mesh->triangleCnt; i++) {
         transformedTris[i] = mesh->triangles[i];
-        mathMultiply(&transformedTris[i].vertex[0].pt, transform);
-        mathMultiply(&transformedTris[i].vertex[1].pt, transform);
-        mathMultiply(&transformedTris[i].vertex[2].pt, transform);
+        transformedTris[i].vertex[0].pt *= *transform;
+        transformedTris[i].vertex[1].pt *= *transform;
+        transformedTris[i].vertex[2].pt *= *transform;
 
         if (transformedTris[i].vertex[0].pt.y < ys) ys = transformedTris[i].vertex[0].pt.y;
         else if (transformedTris[i].vertex[0].pt.y > ye) ye = transformedTris[i].vertex[0].pt.y;

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

@@ -78,7 +78,6 @@ struct SwShapeTask : SwTask
 {
     SwShape shape;
     const RenderShape* rshape = nullptr;
-    bool cmpStroking = false;
     bool clipper = false;
 
     /* We assume that if the stroke width is greater than 2,

+ 2 - 5
thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp

@@ -928,7 +928,7 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& ren
     rw.cellYCnt = rw.cellMax.y - rw.cellMin.y;
     rw.ySpan = 0;
     rw.outline = const_cast<SwOutline*>(outline);
-    rw.bandSize = rw.bufferSize / (sizeof(Cell) * 8);  //bandSize: 64
+    rw.bandSize = rw.bufferSize / (sizeof(Cell) * 2);  //bandSize: 256
     rw.bandShoot = 0;
     rw.antiAlias = antiAlias;
 
@@ -966,10 +966,7 @@ SwRleData* rleRender(SwRleData* rle, const SwOutline* outline, const SwBBox& ren
 
             if (cellMod > 0) cellStart += sizeof(Cell) - cellMod;
 
-            auto cellEnd = rw.bufferSize;
-            cellEnd -= cellEnd % sizeof(Cell);
-
-            auto cellsMax = reinterpret_cast<Cell*>((char*)rw.buffer + cellEnd);
+            auto cellsMax = reinterpret_cast<Cell*>((char*)rw.buffer + rw.bufferSize);
             rw.cells = reinterpret_cast<Cell*>((char*)rw.buffer + cellStart);
 
             if (rw.cells >= cellsMax) goto reduce_bands;

+ 102 - 95
thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp

@@ -107,7 +107,7 @@ static void _dashLineTo(SwDashStroke& dash, const Point* to, const Matrix* trans
     if (mathZero(len)) {
         _outlineMoveTo(*dash.outline, &dash.ptCur, transform);
     //draw the current line fully
-    } else if (len < dash.curLen) {
+    } else if (len <= dash.curLen) {
         dash.curLen -= len;
         if (!dash.curOpGap) {
             if (dash.move) {
@@ -168,7 +168,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
     //draw the current line fully
     if (mathZero(len)) {
         _outlineMoveTo(*dash.outline, &dash.ptCur, transform);
-    } else if (len < dash.curLen) {
+    } else if (len <= dash.curLen) {
         dash.curLen -= len;
         if (!dash.curOpGap) {
             if (dash.move) {
@@ -245,7 +245,86 @@ static void _dashMoveTo(SwDashStroke& dash, uint32_t offIdx, float offset, const
 }
 
 
-static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, float length, SwMpool* mpool, unsigned tid)
+static void _trimPattern(SwDashStroke* dash, const RenderShape* rshape, float length)
+{
+    auto begin = length * rshape->stroke->trim.begin;
+    auto end = length * rshape->stroke->trim.end;
+
+    //default
+    if (end > begin) {
+        if (begin > 0.0f) dash->cnt = 4;
+        else dash->cnt = 2;
+        //looping
+    } else dash->cnt = 3;
+
+    if (dash->cnt == 2) {
+        dash->pattern[0] = end - begin;
+        dash->pattern[1] = length - (end - begin);
+    } else if (dash->cnt == 3) {
+        dash->pattern[0] = end;
+        dash->pattern[1] = (begin - end);
+        dash->pattern[2] = length - begin;
+    } else {
+        dash->pattern[0] = 0;     //zero dash to start with a space.
+        dash->pattern[1] = begin;
+        dash->pattern[2] = end - begin;
+        dash->pattern[3] = length - end;
+    }
+}
+
+
+static float _outlineLength(const RenderShape* rshape, uint32_t shiftPts, uint32_t shiftCmds, bool subpath)
+{
+    const PathCommand* cmds = rshape->path.cmds.data + shiftCmds;
+    auto cmdCnt = rshape->path.cmds.count - shiftCmds;
+    const Point* pts = rshape->path.pts.data + shiftPts;
+    auto ptsCnt = rshape->path.pts.count - shiftPts;
+
+    //No actual shape data
+    if (cmdCnt <= 0 || ptsCnt <= 0) return 0.0f;
+
+    const Point* close = nullptr;
+    auto length = 0.0f;
+
+    //must begin with moveTo
+    if (cmds[0] == PathCommand::MoveTo) {
+        close = pts;
+        cmds++;
+        pts++;
+        cmdCnt--;
+    }
+
+    while (cmdCnt-- > 0) {
+        switch (*cmds) {
+            case PathCommand::Close: {
+                length += mathLength(pts - 1, close);
+                if (subpath) return length;
+                break;
+            }
+            case PathCommand::MoveTo: {
+                if (subpath) return length;
+                close = pts;
+                ++pts;
+                break;
+            }
+            case PathCommand::LineTo: {
+                length += mathLength(pts - 1, pts);
+                ++pts;
+                break;
+            }
+            case PathCommand::CubicTo: {
+                length += bezLength({*(pts - 1), *pts, *(pts + 1), *(pts + 2)});
+                pts += 3;
+                break;
+            }
+        }
+        ++cmds;
+    }
+    return length;
+}
+
+
+static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* transform, bool trimmed, SwMpool* mpool, unsigned tid)
 {
     const PathCommand* cmds = rshape->path.cmds.data;
     auto cmdCnt = rshape->path.cmds.count;
@@ -255,49 +334,23 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
     //No actual shape data
     if (cmdCnt == 0 || ptsCnt == 0) return nullptr;
 
+    auto startPts = pts;
+    auto startCmds = cmds;
+
     SwDashStroke dash;
     auto offset = 0.0f;
-    auto trimmed = false;
-
     dash.cnt = rshape->strokeDash((const float**)&dash.pattern, &offset);
+    auto simultaneous = rshape->stroke->trim.simultaneous;
 
-    //dash by trimming.
-    if (length > 0.0f && dash.cnt == 0) {
-        auto begin = length * rshape->stroke->trim.begin;
-        auto end = length * rshape->stroke->trim.end;
-
-        //TODO: mix trimming + dash style
-
-        //default
-        if (end > begin) {
-            if (begin > 0.0f) dash.cnt += 4;
-            else dash.cnt += 2;
-        //looping
-        } else dash.cnt += 3;
-
-        dash.pattern = (float*)malloc(sizeof(float) * dash.cnt);
-
-        if (dash.cnt == 2) {
-            dash.pattern[0] = end - begin;
-            dash.pattern[1] = length - (end - begin);
-        } else if (dash.cnt == 3) {
-            dash.pattern[0] = end;
-            dash.pattern[1] = (begin - end);
-            dash.pattern[2] = length - begin;
-        } else {
-            dash.pattern[0] = 0;     //zero dash to start with a space.
-            dash.pattern[1] = begin;
-            dash.pattern[2] = end - begin;
-            dash.pattern[3] = length - end;
-        }
-
-        trimmed = true;
-    //just a dasy style.
+    if (dash.cnt == 0) {
+        if (trimmed) dash.pattern = (float*)malloc(sizeof(float) * 4);
+        else return nullptr;
     } else {
-        if (dash.cnt == 0) return nullptr;
+        //TODO: handle dash + trim - for now trimming ignoring is forced
+        trimmed = false;
     }
 
-    //offset?
+    //offset
     auto patternLength = 0.0f;
     uint32_t offIdx = 0;
     if (!mathZero(offset)) {
@@ -319,6 +372,7 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
 
     //must begin with moveTo
     if (cmds[0] == PathCommand::MoveTo) {
+        if (trimmed) _trimPattern(&dash, rshape, _outlineLength(rshape, 0, 0, simultaneous));
         _dashMoveTo(dash, offIdx, offset, pts);
         cmds++;
         pts++;
@@ -331,8 +385,12 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
                 break;
             }
             case PathCommand::MoveTo: {
-                if (rshape->stroke->trim.individual) _dashMoveTo(dash, pts);
-                else _dashMoveTo(dash, offIdx, offset, pts);
+                if (trimmed) {
+                    if (simultaneous) {
+                        _trimPattern(&dash, rshape, _outlineLength(rshape, pts - startPts, cmds - startCmds, true));
+                        _dashMoveTo(dash, offIdx, offset, pts);
+                    } else _dashMoveTo(dash, pts);
+                } else _dashMoveTo(dash, offIdx, offset, pts);
                 ++pts;
                 break;
             }
@@ -358,56 +416,6 @@ static SwOutline* _genDashOutline(const RenderShape* rshape, const Matrix* trans
 }
 
 
-static float _outlineLength(const RenderShape* rshape)
-{
-    const PathCommand* cmds = rshape->path.cmds.data;
-    auto cmdCnt = rshape->path.cmds.count;
-    const Point* pts = rshape->path.pts.data;
-    auto ptsCnt = rshape->path.pts.count;
-
-    //No actual shape data
-    if (cmdCnt == 0 || ptsCnt == 0) return 0.0f;
-
-    const Point* close = nullptr;
-    auto length = 0.0f;
-    auto slength = -1.0f;
-    auto simultaneous = !rshape->stroke->trim.individual;
-
-    //Compute the whole length
-    while (cmdCnt-- > 0) {
-        switch (*cmds) {
-            case PathCommand::Close: {
-                length += mathLength(pts - 1, close);
-                //retrieve the max length of the shape if the simultaneous mode.
-                if (simultaneous) {
-                    if (slength < length) slength = length;
-                    length = 0.0f;
-                }
-                break;
-            }
-            case PathCommand::MoveTo: {
-                close = pts;
-                ++pts;
-                break;
-            }
-            case PathCommand::LineTo: {
-                length += mathLength(pts - 1, pts);
-                ++pts;
-                break;
-            }
-            case PathCommand::CubicTo: {
-                length += bezLength({*(pts - 1), *pts, *(pts + 1), *(pts + 2)});
-                pts += 3;
-                break;
-            }
-        }
-        ++cmds;
-    }
-    if (simultaneous && slength > length) return slength;
-    else return length;
-}
-
-
 static bool _axisAlignedRect(const SwOutline* outline)
 {
     //Fast Track: axis-aligned rectangle?
@@ -584,11 +592,10 @@ bool shapeGenStrokeRle(SwShape* shape, const RenderShape* rshape, const Matrix*
     auto dashStroking = false;
     auto ret = true;
 
-    auto length = rshape->strokeTrim() ? _outlineLength(rshape) : 0.0f;
-
     //Dash style (+trimming)
-    if (rshape->stroke->dashCnt > 0 || length > 0) {
-        shapeOutline = _genDashOutline(rshape, transform, length, mpool, tid);
+    auto trimmed = rshape->strokeTrim();
+    if (rshape->stroke->dashCnt > 0 || trimmed) {
+        shapeOutline = _genDashOutline(rshape, transform, trimmed, mpool, tid);
         if (!shapeOutline) return false;
         dashStroking = true;
     //Normal style

+ 5 - 5
thirdparty/thorvg/src/renderer/tvgPaint.cpp

@@ -75,13 +75,13 @@ static Result _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform
         auto v2 = *pt3;
 
         if (rTransform) {
-            mathMultiply(&v1, &rTransform->m);
-            mathMultiply(&v2, &rTransform->m);
+            v1 *= rTransform->m;
+            v2 *= rTransform->m;
         }
 
         if (pTransform) {
-            mathMultiply(&v1, &pTransform->m);
-            mathMultiply(&v2, &pTransform->m);
+            v1 *= pTransform->m;
+            v2 *= pTransform->m;
         }
 
         //sorting
@@ -327,7 +327,7 @@ bool Paint::Impl::bounds(float* x, float* y, float* w, float* h, bool transforme
 
     //Compute the AABB after transformation
     for (int i = 0; i < 4; i++) {
-        mathMultiply(&pt[i], m);
+        pt[i] *= *m;
 
         if (pt[i].x < x1) x1 = pt[i].x;
         if (pt[i].x > x2) x2 = pt[i].x;

+ 2 - 2
thirdparty/thorvg/src/renderer/tvgRender.cpp

@@ -47,7 +47,7 @@ void RenderTransform::update()
 
     mathScale(&m, scale, scale);
 
-    if (!mathZero(degree)) mathRotate(&m, degree);
+    mathRotate(&m, degree);
 
     mathTranslate(&m, x, y);
 }
@@ -55,7 +55,7 @@ void RenderTransform::update()
 
 RenderTransform::RenderTransform(const RenderTransform* lhs, const RenderTransform* rhs)
 {
-    if (lhs && rhs) m = mathMultiply(&lhs->m, &rhs->m);
+    if (lhs && rhs) m = lhs->m * rhs->m;
     else if (lhs) m = lhs->m;
     else if (rhs) m = rhs->m;
     else mathIdentity(&m);

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

@@ -142,7 +142,7 @@ struct RenderStroke
     struct {
         float begin = 0.0f;
         float end = 1.0f;
-        bool individual = false;
+        bool simultaneous = true;
     } trim;
 
     ~RenderStroke()

+ 22 - 13
thirdparty/thorvg/src/renderer/tvgShape.cpp

@@ -287,16 +287,14 @@ const Fill* Shape::fill() const noexcept
 
 Result Shape::order(bool strokeFirst) noexcept
 {
-    if (!pImpl->strokeFirst(strokeFirst)) return Result::FailedAllocation;
-
+    pImpl->strokeFirst(strokeFirst);
     return Result::Success;
 }
 
 
 Result Shape::stroke(float width) noexcept
 {
-    if (!pImpl->strokeWidth(width)) return Result::FailedAllocation;
-
+    pImpl->strokeWidth(width);
     return Result::Success;
 }
 
@@ -309,8 +307,7 @@ float Shape::strokeWidth() const noexcept
 
 Result Shape::stroke(uint8_t r, uint8_t g, uint8_t b, uint8_t a) noexcept
 {
-    if (!pImpl->strokeColor(r, g, b, a)) return Result::FailedAllocation;
-
+    pImpl->strokeColor(r, g, b, a);
     return Result::Success;
 }
 
@@ -349,27 +346,25 @@ uint32_t Shape::strokeDash(const float** dashPattern) const noexcept
 
 Result Shape::stroke(StrokeCap cap) noexcept
 {
-    if (!pImpl->strokeCap(cap)) return Result::FailedAllocation;
-
+    pImpl->strokeCap(cap);
     return Result::Success;
 }
 
 
 Result Shape::stroke(StrokeJoin join) noexcept
 {
-    if (!pImpl->strokeJoin(join)) return Result::FailedAllocation;
-
+    pImpl->strokeJoin(join);
     return Result::Success;
 }
 
+
 Result Shape::strokeMiterlimit(float miterlimit) noexcept
 {
     // https://www.w3.org/TR/SVG2/painting.html#LineJoin
     // - A negative value for stroke-miterlimit must be treated as an illegal value.
-    if (miterlimit < 0.0f) return Result::NonSupport;
+    if (miterlimit < 0.0f) return Result::InvalidArguments;
     // TODO Find out a reasonable max value.
-    if (!pImpl->strokeMiterlimit(miterlimit)) return Result::FailedAllocation;
-
+    pImpl->strokeMiterlimit(miterlimit);
     return Result::Success;
 }
 
@@ -385,12 +380,26 @@ StrokeJoin Shape::strokeJoin() const noexcept
     return pImpl->rs.strokeJoin();
 }
 
+
 float Shape::strokeMiterlimit() const noexcept
 {
     return pImpl->rs.strokeMiterlimit();
 }
 
 
+Result Shape::strokeTrim(float begin, float end, bool simultaneous) noexcept
+{
+    pImpl->strokeTrim(begin, end, simultaneous);
+    return Result::Success;
+}
+
+
+bool Shape::strokeTrim(float* begin, float* end) const noexcept
+{
+    return pImpl->strokeTrim(begin, end);
+}
+
+
 Result Shape::fill(FillRule r) noexcept
 {
     pImpl->rs.rule = r;

+ 40 - 23
thirdparty/thorvg/src/renderer/tvgShape.h

@@ -207,60 +207,81 @@ struct Shape::Impl
         flag |= RenderUpdateFlag::Path;
     }
 
-    bool strokeWidth(float width)
+    void strokeWidth(float width)
     {
         if (!rs.stroke) rs.stroke = new RenderStroke();
         rs.stroke->width = width;
         flag |= RenderUpdateFlag::Stroke;
-
-        return true;
     }
 
-    bool strokeTrim(float begin, float end, bool individual)
+    void strokeTrim(float begin, float end, bool simultaneous)
     {
         if (!rs.stroke) {
-            if (begin == 0.0f && end == 1.0f) return true;
+            if (begin == 0.0f && end == 1.0f) return;
             rs.stroke = new RenderStroke();
         }
 
-        if (mathEqual(rs.stroke->trim.begin, begin) && mathEqual(rs.stroke->trim.end, end)) return true;
+        if (mathEqual(rs.stroke->trim.begin, begin) && mathEqual(rs.stroke->trim.end, end) &&
+            rs.stroke->trim.simultaneous == simultaneous) return;
+
+        auto loop = true;
+
+        if (begin > 1.0f && end > 1.0f) loop = false;
+        if (begin < 0.0f && end < 0.0f) loop = false;
+        if (begin >= 0.0f && begin <= 1.0f && end >= 0.0f  && end <= 1.0f) loop = false;
+
+        if (begin > 1.0f) begin -= 1.0f;
+        if (begin < 0.0f) begin += 1.0f;
+        if (end > 1.0f) end -= 1.0f;
+        if (end < 0.0f) end += 1.0f;
+
+        if ((loop && begin < end) || (!loop && begin > end)) {
+            auto tmp = begin;
+            begin = end;
+            end = tmp;
+        }
 
         rs.stroke->trim.begin = begin;
         rs.stroke->trim.end = end;
-        rs.stroke->trim.individual = individual;
+        rs.stroke->trim.simultaneous = simultaneous;
         flag |= RenderUpdateFlag::Stroke;
+    }
 
-        return true;
+    bool strokeTrim(float* begin, float* end)
+    {
+        if (rs.stroke) {
+            if (begin) *begin = rs.stroke->trim.begin;
+            if (end) *end = rs.stroke->trim.end;
+            return rs.stroke->trim.simultaneous;
+        } else {
+            if (begin) *begin = 0.0f;
+            if (end) *end = 1.0f;
+            return false;
+        }
     }
 
-    bool strokeCap(StrokeCap cap)
+    void strokeCap(StrokeCap cap)
     {
         if (!rs.stroke) rs.stroke = new RenderStroke();
         rs.stroke->cap = cap;
         flag |= RenderUpdateFlag::Stroke;
-
-        return true;
     }
 
-    bool strokeJoin(StrokeJoin join)
+    void strokeJoin(StrokeJoin join)
     {
         if (!rs.stroke) rs.stroke = new RenderStroke();
         rs.stroke->join = join;
         flag |= RenderUpdateFlag::Stroke;
-
-        return true;
     }
 
-    bool strokeMiterlimit(float miterlimit)
+    void strokeMiterlimit(float miterlimit)
     {
         if (!rs.stroke) rs.stroke = new RenderStroke();
         rs.stroke->miterlimit = miterlimit;
         flag |= RenderUpdateFlag::Stroke;
-
-        return true;
     }
 
-    bool strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
+    void strokeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
     {
         if (!rs.stroke) rs.stroke = new RenderStroke();
         if (rs.stroke->fill) {
@@ -275,8 +296,6 @@ struct Shape::Impl
         rs.stroke->color[3] = a;
 
         flag |= RenderUpdateFlag::Stroke;
-
-        return true;
     }
 
     Result strokeFill(unique_ptr<Fill> f)
@@ -335,13 +354,11 @@ struct Shape::Impl
         return rs.stroke->strokeFirst;
     }
 
-    bool strokeFirst(bool strokeFirst)
+    void strokeFirst(bool strokeFirst)
     {
         if (!rs.stroke) rs.stroke = new RenderStroke();
         rs.stroke->strokeFirst = strokeFirst;
         flag |= RenderUpdateFlag::Stroke;
-
-        return true;
     }
 
     void update(RenderUpdateFlag flag)

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

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