diff --git a/thirdparty/README.md b/thirdparty/README.md index 137e3a0cbce..6878af863f0 100644 --- a/thirdparty/README.md +++ b/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: diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 9c83f25c79b..699076fdf1a 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/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 diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index f7396050d76..8285aa1c4ce 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/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 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. * diff --git a/thirdparty/thorvg/src/common/tvgCompressor.cpp b/thirdparty/thorvg/src/common/tvgCompressor.cpp index 9a1dc546320..b61718f9a7b 100644 --- a/thirdparty/thorvg/src/common/tvgCompressor.cpp +++ b/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; +} + } diff --git a/thirdparty/thorvg/src/common/tvgCompressor.h b/thirdparty/thorvg/src/common/tvgCompressor.h index 0756127ec61..b043cc77dea 100644 --- a/thirdparty/thorvg/src/common/tvgCompressor.h +++ b/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_ diff --git a/thirdparty/thorvg/src/common/tvgMath.cpp b/thirdparty/thorvg/src/common/tvgMath.cpp index 37a8879cb56..e6b5d470503 100644 --- a/thirdparty/thorvg/src/common/tvgMath.cpp +++ b/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; } diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h index 5c2966956af..0f877d919e8 100644 --- a/thirdparty/thorvg/src/common/tvgMath.h +++ b/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 static inline T mathLerp(const T &start, const T &end, float t) { diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index 0a47112084b..f59994aae6f 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/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; diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp index 0b2113dd071..7e7efed3fc5 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/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(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 _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 _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 _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 _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); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp index 3d582d291c8..be1662daeb6 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp +++ b/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; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp index b85d9438732..3431f034116 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMemPool.cpp +++ b/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(calloc(sizeof(SwMpool), 1)); + auto mpool = static_cast(calloc(1, sizeof(SwMpool))); mpool->outline = static_cast(calloc(1, sizeof(SwOutline) * allocSize)); mpool->strokeOutline = static_cast(calloc(1, sizeof(SwOutline) * allocSize)); mpool->dashOutline = static_cast(calloc(1, sizeof(SwOutline) * allocSize)); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h index 731f6984e3a..8ec2bc0c47e 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRasterTexmap.h +++ b/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; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index 0b2940c32d3..f689179928a 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/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, diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp index 386cc594b43..1e5c4ef4094 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp +++ b/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(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((char*)rw.buffer + cellEnd); + auto cellsMax = reinterpret_cast((char*)rw.buffer + rw.bufferSize); rw.cells = reinterpret_cast((char*)rw.buffer + cellStart); if (rw.cells >= cellsMax) goto reduce_bands; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index b9327374b60..d8dd40d45b1 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/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 diff --git a/thirdparty/thorvg/src/renderer/tvgPaint.cpp b/thirdparty/thorvg/src/renderer/tvgPaint.cpp index 227ce10a0d6..fcb632e2b1a 100644 --- a/thirdparty/thorvg/src/renderer/tvgPaint.cpp +++ b/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; diff --git a/thirdparty/thorvg/src/renderer/tvgRender.cpp b/thirdparty/thorvg/src/renderer/tvgRender.cpp index 14f77571fb1..9c779f7c003 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.cpp +++ b/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); diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index 6ea516c2f9d..8f28d37dbc1 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/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() diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp index 4cc8f64900b..c010aa7bbfc 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.cpp +++ b/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; diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index 55335214bed..4e85db37d0b 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/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 strokeCap(StrokeCap cap) + 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; + } + } + + 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 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) diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index cd1aeadec06..c980b89c4b6 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/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/