diff --git a/thirdparty/README.md b/thirdparty/README.md index 59b9203960ef..145f0d427e40 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -861,13 +861,13 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.12.5 (9c8eeaab9629b5d241b1092a3398fe6351c259cd, 2024) +- Version: 0.12.7 (cddae9966cbb48c431ea17c262d6f48393206fd7, 2024) - License: MIT Files extracted from upstream source: See `thorvg/update-thorvg.sh` for extraction instructions. Set the version -number and run the script and apply patches from the `patches` folder. +number and run the script. ## ufbx diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index c5745dab1bdf..1133b99e6409 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -10,5 +10,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.12.5" +#define THORVG_VERSION_STRING "0.12.7" #endif diff --git a/thirdparty/thorvg/inc/thorvg.h b/thirdparty/thorvg/inc/thorvg.h index 6aee53f7e07d..d4fa5c871203 100644 --- a/thirdparty/thorvg/inc/thorvg.h +++ b/thirdparty/thorvg/inc/thorvg.h @@ -1223,6 +1223,10 @@ class TVG_API Picture final : public Paint /** * @brief Loads a picture data directly from a file. * + * ThorVG efficiently caches the loaded data using the specified @p path as a key. + * This means that loading the same file again will not result in duplicate operations; + * instead, ThorVG will reuse the previously loaded picture data. + * * @param[in] path A path to the picture file. * * @retval Result::Success When succeed. @@ -1238,6 +1242,10 @@ class TVG_API Picture final : public Paint /** * @brief Loads a picture data from a memory block of a given size. * + * ThorVG efficiently caches the loaded data using the specified @p data address as a key + * when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations + * for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data. + * * @param[in] data A pointer to a memory location where the content of the picture file is stored. * @param[in] size The size in bytes of the memory occupied by the @p data. * @param[in] copy Decides whether the data should be copied into the engine local buffer. @@ -1299,6 +1307,10 @@ class TVG_API Picture final : public Paint /** * @brief Loads a raw data from a memory block with a given size. * + * ThorVG efficiently caches the loaded data using the specified @p data address as a key + * when the @p copy has @c false. This means that loading the same data again will not result in duplicate operations + * for the sharable @p data. Instead, ThorVG will reuse the previously loaded picture data. + * * @param[in] paint A Tvg_Paint pointer to the picture object. * @param[in] data A pointer to a memory location where the content of the picture raw data is stored. * @param[in] w The width of the image @p data in pixels. @@ -1544,6 +1556,10 @@ class TVG_API Text final : public Paint /** * @brief Loads a scalable font data(ttf) from a file. * + * ThorVG efficiently caches the loaded data using the specified @p path as a key. + * This means that loading the same file again will not result in duplicate operations; + * instead, ThorVG will reuse the previously loaded font data. + * * @param[in] path The path to the font file. * * @retval Result::Success When succeed. diff --git a/thirdparty/thorvg/patches/Fix_compiler_shadowing_warning.patch b/thirdparty/thorvg/patches/Fix_compiler_shadowing_warning.patch deleted file mode 100644 index e0647628d360..000000000000 --- a/thirdparty/thorvg/patches/Fix_compiler_shadowing_warning.patch +++ /dev/null @@ -1,23 +0,0 @@ -diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h -index e6d993a41e..5dd3d5a624 100644 ---- a/thirdparty/thorvg/src/common/tvgLock.h -+++ b/thirdparty/thorvg/src/common/tvgLock.h -@@ -38,10 +38,10 @@ namespace tvg { - { - Key* key = nullptr; - -- ScopedLock(Key& key) -+ ScopedLock(Key& k) - { -- key.mtx.lock(); -- this->key = &key; -+ k.mtx.lock(); -+ key = &k; - } - - ~ScopedLock() -@@ -68,3 +68,4 @@ namespace tvg { - #endif //THORVG_THREAD_SUPPORT - - #endif //_TVG_LOCK_H_ -+ diff --git a/thirdparty/thorvg/src/common/tvgArray.h b/thirdparty/thorvg/src/common/tvgArray.h index acb3a41b9732..d95df40460bc 100644 --- a/thirdparty/thorvg/src/common/tvgArray.h +++ b/thirdparty/thorvg/src/common/tvgArray.h @@ -90,6 +90,16 @@ struct Array return data[idx]; } + const T* begin() const + { + return data; + } + + T* begin() + { + return data; + } + T* end() { return data + count; diff --git a/thirdparty/thorvg/src/common/tvgBezier.cpp b/thirdparty/thorvg/src/common/tvgBezier.cpp index 5fb501721e2c..8c19afa32a8b 100644 --- a/thirdparty/thorvg/src/common/tvgBezier.cpp +++ b/thirdparty/thorvg/src/common/tvgBezier.cpp @@ -29,7 +29,7 @@ /* Internal Class Implementation */ /************************************************************************/ -static float _lineLength(const Point& pt1, const Point& pt2) +static float _lineLengthApprox(const Point& pt1, const Point& pt2) { /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. With alpha = 1, beta = 3/8, giving results with the largest error less @@ -41,6 +41,59 @@ static float _lineLength(const Point& pt1, const Point& pt2) } +static float _lineLength(const Point& pt1, const Point& pt2) +{ + Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; + return sqrtf(diff.x * diff.x + diff.y * diff.y); +} + + +template +float _bezLength(const Bezier& cur, LengthFunc lineLengthFunc) +{ + Bezier left, right; + auto len = lineLengthFunc(cur.start, cur.ctrl1) + lineLengthFunc(cur.ctrl1, cur.ctrl2) + lineLengthFunc(cur.ctrl2, cur.end); + auto chord = lineLengthFunc(cur.start, cur.end); + + if (fabsf(len - chord) > BEZIER_EPSILON) { + tvg::bezSplit(cur, left, right); + return _bezLength(left, lineLengthFunc) + _bezLength(right, lineLengthFunc); + } + return len; +} + + +template +float _bezAt(const Bezier& bz, float at, float length, LengthFunc lineLengthFunc) +{ + auto biggest = 1.0f; + auto smallest = 0.0f; + auto t = 0.5f; + + //just in case to prevent an infinite loop + if (at <= 0) return 0.0f; + if (at >= length) return 1.0f; + + while (true) { + auto right = bz; + Bezier left; + bezSplitLeft(right, t, left); + length = _bezLength(left, lineLengthFunc); + if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) { + break; + } + if (length < at) { + smallest = t; + t = (t + biggest) * 0.5f; + } else { + biggest = t; + t = (smallest + t) * 0.5f; + } + } + return t; +} + + /************************************************************************/ /* External Class Implementation */ /************************************************************************/ @@ -48,7 +101,7 @@ static float _lineLength(const Point& pt1, const Point& pt2) namespace tvg { -void bezSplit(const Bezier&cur, Bezier& left, Bezier& right) +void bezSplit(const Bezier& cur, Bezier& left, Bezier& right) { auto c = (cur.ctrl1.x + cur.ctrl2.x) * 0.5f; left.ctrl1.x = (cur.start.x + cur.ctrl1.x) * 0.5f; @@ -72,15 +125,13 @@ void bezSplit(const Bezier&cur, Bezier& left, Bezier& right) float bezLength(const Bezier& cur) { - Bezier left, right; - auto len = _lineLength(cur.start, cur.ctrl1) + _lineLength(cur.ctrl1, cur.ctrl2) + _lineLength(cur.ctrl2, cur.end); - auto chord = _lineLength(cur.start, cur.end); + return _bezLength(cur, _lineLength); +} - if (fabsf(len - chord) > BEZIER_EPSILON) { - bezSplit(cur, left, right); - return bezLength(left) + bezLength(right); - } - return len; + +float bezLengthApprox(const Bezier& cur) +{ + return _bezLength(cur, _lineLengthApprox); } @@ -110,31 +161,13 @@ void bezSplitLeft(Bezier& cur, float at, Bezier& left) float bezAt(const Bezier& bz, float at, float length) { - auto biggest = 1.0f; - auto smallest = 0.0f; - auto t = 0.5f; + return _bezAt(bz, at, length, _lineLength); +} - //just in case to prevent an infinite loop - if (at <= 0) return 0.0f; - if (at >= length) return 1.0f; - while (true) { - auto right = bz; - Bezier left; - bezSplitLeft(right, t, left); - length = bezLength(left); - if (fabsf(length - at) < BEZIER_EPSILON || fabsf(smallest - biggest) < BEZIER_EPSILON) { - break; - } - if (length < at) { - smallest = t; - t = (t + biggest) * 0.5f; - } else { - biggest = t; - t = (smallest + t) * 0.5f; - } - } - return t; +float bezAtApprox(const Bezier& bz, float at, float length) +{ + return _bezAt(bz, at, length, _lineLengthApprox); } diff --git a/thirdparty/thorvg/src/common/tvgBezier.h b/thirdparty/thorvg/src/common/tvgBezier.h index cb2766c50553..80a199258a12 100644 --- a/thirdparty/thorvg/src/common/tvgBezier.h +++ b/thirdparty/thorvg/src/common/tvgBezier.h @@ -44,6 +44,8 @@ void bezSplitAt(const Bezier& cur, float at, Bezier& left, Bezier& right); Point bezPointAt(const Bezier& bz, float t); float bezAngleAt(const Bezier& bz, float t); +float bezLengthApprox(const Bezier& cur); +float bezAtApprox(const Bezier& bz, float at, float length); } #endif //_TVG_BEZIER_H_ diff --git a/thirdparty/thorvg/src/common/tvgLock.h b/thirdparty/thorvg/src/common/tvgLock.h index 8bf1534605a0..5dd3d5a62485 100644 --- a/thirdparty/thorvg/src/common/tvgLock.h +++ b/thirdparty/thorvg/src/common/tvgLock.h @@ -68,3 +68,4 @@ namespace tvg { #endif //THORVG_THREAD_SUPPORT #endif //_TVG_LOCK_H_ + diff --git a/thirdparty/thorvg/src/common/tvgMath.h b/thirdparty/thorvg/src/common/tvgMath.h index 50c3458efc82..7f6708262be7 100644 --- a/thirdparty/thorvg/src/common/tvgMath.h +++ b/thirdparty/thorvg/src/common/tvgMath.h @@ -31,6 +31,7 @@ #define MATH_PI 3.14159265358979323846f #define MATH_PI2 1.57079632679489661923f +#define PATH_KAPPA 0.552284f #define mathMin(x, y) (((x) < (y)) ? (x) : (y)) #define mathMax(x, y) (((x) > (y)) ? (x) : (y)) diff --git a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp index 9c57c665ca4c..35351f71305a 100644 --- a/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp +++ b/thirdparty/thorvg/src/loaders/png/tvgPngLoader.cpp @@ -47,9 +47,6 @@ void PngLoader::run(unsigned tid) surface.h = height; surface.cs = ColorSpace::ABGR8888; surface.channelSize = sizeof(uint32_t); - - if (state.info_png.color.colortype == LCT_RGBA) surface.premultiplied = false; - else surface.premultiplied = true; } diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp index ab795fd90853..7a4f5445398f 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgLoader.cpp @@ -89,6 +89,7 @@ static char* _skipSpace(const char* str, const char* end) static char* _copyId(const char* str) { if (!str) return nullptr; + if (strlen(str) == 0) return nullptr; return strdup(str); } @@ -377,19 +378,25 @@ static void _parseDashArray(SvgLoaderData* loader, const char *str, SvgDash* das static char* _idFromUrl(const char* url) { - url = _skipSpace(url, nullptr); - if ((*url) == '(') { - ++url; - url = _skipSpace(url, nullptr); - } + auto open = strchr(url, '('); + auto close = strchr(url, ')'); + if (!open || !close || open >= close) return nullptr; + + open = strchr(url, '#'); + if (!open || open >= close) return nullptr; + + ++open; + --close; - if ((*url) == '\'') ++url; - if ((*url) == '#') ++url; + //trim the rest of the spaces if any + while (open < close && *close == ' ') --close; + + //quick verification + for (auto id = open; id < close; id++) { + if (*id == ' ' || *id == '\'') return nullptr; + } - int i = 0; - while (url[i] > ' ' && url[i] != ')' && url[i] != '\'') ++i; - - return strDuplicate(url, i); + return strDuplicate(open, (close - open + 1)); } @@ -3494,7 +3501,7 @@ void SvgLoader::clear(bool all) free(loaderData.svgParse); loaderData.svgParse = nullptr; - for (auto gradient = loaderData.gradients.data; gradient < loaderData.gradients.end(); ++gradient) { + for (auto gradient = loaderData.gradients.begin(); gradient < loaderData.gradients.end(); ++gradient) { (*gradient)->clear(); free(*gradient); } @@ -3506,7 +3513,7 @@ void SvgLoader::clear(bool all) if (!all) return; - for (auto p = loaderData.images.data; p < loaderData.images.end(); ++p) { + for (auto p = loaderData.images.begin(); p < loaderData.images.end(); ++p) { free(*p); } loaderData.images.reset(); diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp index 674c30f5bd58..b9084cd05061 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -409,7 +409,7 @@ static bool _recognizeShape(SvgNode* node, Shape* shape) } case SvgNodeType::Polygon: { if (node->node.polygon.pts.count < 2) break; - auto pts = node->node.polygon.pts.data; + auto pts = node->node.polygon.pts.begin(); shape->moveTo(pts[0], pts[1]); for (pts += 2; pts < node->node.polygon.pts.end(); pts += 2) { shape->lineTo(pts[0], pts[1]); @@ -419,7 +419,7 @@ static bool _recognizeShape(SvgNode* node, Shape* shape) } case SvgNodeType::Polyline: { if (node->node.polyline.pts.count < 2) break; - auto pts = node->node.polyline.pts.data; + auto pts = node->node.polyline.pts.begin(); shape->moveTo(pts[0], pts[1]); for (pts += 2; pts < node->node.polyline.pts.end(); pts += 2) { shape->lineTo(pts[0], pts[1]); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp index 8956cd9f2464..60763068d49d 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwFill.cpp @@ -201,7 +201,13 @@ bool _prepareRadial(SwFill* fill, const RadialGradient* radial, const Matrix* tr fill->radial.fy = cy + r * (fy - cy) / dist; fill->radial.dx = cx - fill->radial.fx; fill->radial.dy = cy - fill->radial.fy; - fill->radial.a = fill->radial.dr * fill->radial.dr - fill->radial.dx * fill->radial.dx - fill->radial.dy * fill->radial.dy; + // Prevent loss of precision on Apple Silicon when dr=dy and dx=0 due to FMA + // https://github.com/thorvg/thorvg/issues/2014 + auto dr2 = fill->radial.dr * fill->radial.dr; + auto dx2 = fill->radial.dx * fill->radial.dx; + auto dy2 = fill->radial.dy * fill->radial.dy; + + fill->radial.a = dr2 - dx2 - dy2; } if (fill->radial.a > 0) fill->radial.invA = 1.0f / fill->radial.a; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp index 42e405195eb0..ad5a2b7371cf 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwMath.cpp @@ -50,12 +50,6 @@ bool mathSmallCubic(const SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, Sw auto d2 = base[1] - base[2]; auto d3 = base[0] - base[1]; - if (d1 == d2 || d2 == d3) { - if (d3.small()) angleIn = angleMid = angleOut = 0; - else angleIn = angleMid = angleOut = mathAtan(d3); - return true; - } - if (d1.small()) { if (d2.small()) { if (d3.small()) { @@ -293,13 +287,13 @@ bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, S { if (!outline) return false; - auto pt = outline->pts.data; - if (outline->pts.empty() || outline->cntrs.empty()) { renderRegion.reset(); return false; } + auto pt = outline->pts.begin(); + auto xMin = pt->x; auto xMax = pt->x; auto yMin = pt->y; diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp index c187af38d5ad..3387905761e4 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRenderer.cpp @@ -182,7 +182,7 @@ struct SwShapeTask : SwTask shapeDelOutline(&shape, mpool, tid); //Clip Path - for (auto clip = clips.data; clip < clips.end(); ++clip) { + for (auto clip = clips.begin(); clip < clips.end(); ++clip) { auto clipper = static_cast(*clip); //Clip shape rle if (shape.rle && !clipper->clip(shape.rle)) goto err; @@ -242,7 +242,7 @@ struct SwSceneTask : SwTask rleMerge(sceneRle, clipper1->rle(), clipper2->rle()); //Unify the remained clippers - for (auto rd = scene.data + 2; rd < scene.end(); ++rd) { + for (auto rd = scene.begin() + 2; rd < scene.end(); ++rd) { auto clipper = static_cast(*rd); rleMerge(sceneRle, sceneRle, clipper->rle()); } @@ -301,7 +301,7 @@ struct SwImageTask : SwTask if (image.rle) { //Clear current task memorypool here if the clippers would use the same memory pool imageDelOutline(&image, mpool, tid); - for (auto clip = clips.data; clip < clips.end(); ++clip) { + for (auto clip = clips.begin(); clip < clips.end(); ++clip) { auto clipper = static_cast(*clip); if (!clipper->clip(image.rle)) goto err; } @@ -377,7 +377,7 @@ SwRenderer::~SwRenderer() bool SwRenderer::clear() { - for (auto task = tasks.data; task < tasks.end(); ++task) { + for (auto task = tasks.begin(); task < tasks.end(); ++task) { if ((*task)->disposed) { delete(*task); } else { @@ -451,7 +451,7 @@ bool SwRenderer::preRender() void SwRenderer::clearCompositors() { //Free Composite Caches - for (auto comp = compositors.data; comp < compositors.end(); ++comp) { + for (auto comp = compositors.begin(); comp < compositors.end(); ++comp) { free((*comp)->compositor->image.data); delete((*comp)->compositor); delete(*comp); @@ -467,7 +467,7 @@ bool SwRenderer::postRender() rasterUnpremultiply(surface); } - for (auto task = tasks.data; task < tasks.end(); ++task) { + for (auto task = tasks.begin(); task < tasks.end(); ++task) { if ((*task)->disposed) delete(*task); else (*task)->pushed = false; } @@ -624,7 +624,7 @@ Compositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs) auto reqChannelSize = CHANNEL_SIZE(cs); //Use cached data - for (auto p = compositors.data; p < compositors.end(); ++p) { + for (auto p = compositors.begin(); p < compositors.end(); ++p) { if ((*p)->compositor->valid && (*p)->compositor->image.channelSize == reqChannelSize) { cmp = *p; break; @@ -723,7 +723,7 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform, //TODO: Failed threading them. It would be better if it's possible. //See: https://github.com/thorvg/thorvg/issues/1409 //Guarantee composition targets get ready. - for (auto clip = clips.data; clip < clips.end(); ++clip) { + for (auto clip = clips.begin(); clip < clips.end(); ++clip) { static_cast(*clip)->done(); } @@ -784,7 +784,7 @@ RenderData SwRenderer::prepare(const Array& scene, RenderData data, //TODO: Failed threading them. It would be better if it's possible. //See: https://github.com/thorvg/thorvg/issues/1409 //Guarantee composition targets get ready. - for (auto task = scene.data; task < scene.end(); ++task) { + for (auto task = scene.begin(); task < scene.end(); ++task) { static_cast(*task)->done(); } return prepareCommon(task, transform, clips, opacity, flags); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp index 33c94e106383..386cc594b430 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwRle.cpp @@ -713,7 +713,7 @@ static void _decomposeOutline(RleWorker& rw) auto outline = rw.outline; auto first = 0; //index of first point in contour - for (auto cntr = outline->cntrs.data; cntr < outline->cntrs.end(); ++cntr) { + for (auto cntr = outline->cntrs.begin(); cntr < outline->cntrs.end(); ++cntr) { auto last = *cntr; auto limit = outline->pts.data + last; auto start = UPSCALE(outline->pts[first]); diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp index d3b715eab8d1..03261a4b7fc9 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwShape.cpp @@ -37,13 +37,8 @@ struct Line static float _lineLength(const Point& pt1, const Point& pt2) { - /* approximate sqrt(x*x + y*y) using alpha max plus beta min algorithm. - With alpha = 1, beta = 3/8, giving results with the largest error less - than 7% compared to the exact value. */ Point diff = {pt2.x - pt1.x, pt2.y - pt1.y}; - if (diff.x < 0) diff.x = -diff.x; - if (diff.y < 0) diff.y = -diff.y; - return (diff.x > diff.y) ? (diff.x + diff.y * 0.375f) : (diff.y + diff.x * 0.375f); + return sqrtf(diff.x * diff.x + diff.y * diff.y); } diff --git a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp index 8f44cf36164e..9ec4bd78a50d 100644 --- a/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp +++ b/thirdparty/thorvg/src/renderer/sw_engine/tvgSwStroke.cpp @@ -377,9 +377,6 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) //a zero-length lineto is a no-op; avoid creating a spurious corner if (delta.zero()) return; - //compute length of line - auto angle = mathAtan(delta); - /* The lineLength is used to determine the intersection of strokes outlines. The scale needs to be reverted since the stroke width has not been scaled. An alternative option is to scale the width of the stroke properly by @@ -387,6 +384,7 @@ static void _lineTo(SwStroke& stroke, const SwPoint& to) delta.x = static_cast(delta.x / stroke.sx); delta.y = static_cast(delta.y / stroke.sy); auto lineLength = mathLength(delta); + auto angle = mathAtan(delta); delta = {static_cast(stroke.width), 0}; mathRotate(delta, angle + SW_ANGLE_PI2); @@ -835,7 +833,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline) uint32_t first = 0; uint32_t i = 0; - for (auto cntr = outline.cntrs.data; cntr < outline.cntrs.end(); ++cntr, ++i) { + for (auto cntr = outline.cntrs.begin(); cntr < outline.cntrs.end(); ++cntr, ++i) { auto last = *cntr; //index of last point in contour auto limit = outline.pts.data + last; diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp index 995eca7f415a..809c4e98e4e3 100644 --- a/thirdparty/thorvg/src/renderer/tvgAnimation.cpp +++ b/thirdparty/thorvg/src/renderer/tvgAnimation.cpp @@ -20,33 +20,13 @@ * SOFTWARE. */ -#include "tvgCommon.h" #include "tvgFrameModule.h" -#include "tvgPaint.h" -#include "tvgPicture.h" +#include "tvgAnimation.h" /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -struct Animation::Impl -{ - Picture* picture = nullptr; - - Impl() - { - picture = Picture::gen().release(); - PP(picture)->ref(); - } - - ~Impl() - { - if (PP(picture)->unref() == 0) { - delete(picture); - } - } -}; - /************************************************************************/ /* External Class Implementation */ /************************************************************************/ diff --git a/thirdparty/thorvg/src/renderer/tvgAnimation.h b/thirdparty/thorvg/src/renderer/tvgAnimation.h new file mode 100644 index 000000000000..14212eb67add --- /dev/null +++ b/thirdparty/thorvg/src/renderer/tvgAnimation.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TVG_ANIMATION_H_ +#define _TVG_ANIMATION_H_ + +#include "tvgCommon.h" +#include "tvgPaint.h" +#include "tvgPicture.h" + +struct Animation::Impl +{ + Picture* picture = nullptr; + + Impl() + { + picture = Picture::gen().release(); + PP(picture)->ref(); + } + + ~Impl() + { + if (PP(picture)->unref() == 0) { + delete(picture); + } + } +}; + +#endif //_TVG_ANIMATION_H_ diff --git a/thirdparty/thorvg/src/renderer/tvgLoadModule.h b/thirdparty/thorvg/src/renderer/tvgLoadModule.h index 0dc57253ed9f..c75068377129 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoadModule.h +++ b/thirdparty/thorvg/src/renderer/tvgLoadModule.h @@ -32,17 +32,20 @@ struct LoadModule INLIST_ITEM(LoadModule); //Use either hashkey(data) or hashpath(path) - uint64_t hashkey; - char* hashpath = nullptr; + union { + uintptr_t hashkey; + char* hashpath = nullptr; + }; FileType type; //current loader file type uint16_t sharing = 0; //reference count bool readied = false; //read done already. + bool pathcache = false; //cached by path LoadModule(FileType type) : type(type) {} virtual ~LoadModule() { - free(hashpath); + if (pathcache) free(hashpath); } virtual bool open(const string& path) { return false; } @@ -57,6 +60,12 @@ struct LoadModule return true; } + bool cached() + { + if (hashkey) return true; + return false; + } + virtual bool close() { if (sharing == 0) return true; diff --git a/thirdparty/thorvg/src/renderer/tvgLoader.cpp b/thirdparty/thorvg/src/renderer/tvgLoader.cpp index fc93a0cbdcc4..2853b83895c3 100644 --- a/thirdparty/thorvg/src/renderer/tvgLoader.cpp +++ b/thirdparty/thorvg/src/renderer/tvgLoader.cpp @@ -57,9 +57,9 @@ #include "tvgRawLoader.h" -uint64_t HASH_KEY(const char* data, uint64_t size) +uintptr_t HASH_KEY(const char* data) { - return (((uint64_t) data) << 32) | size; + return reinterpret_cast(data); } /************************************************************************/ @@ -219,7 +219,7 @@ static LoadModule* _findFromCache(const string& path) auto loader = _activeLoaders.head; while (loader) { - if (loader->hashpath && !strcmp(loader->hashpath, path.c_str())) { + if (loader->pathcache && !strcmp(loader->hashpath, path.c_str())) { ++loader->sharing; return loader; } @@ -237,7 +237,7 @@ static LoadModule* _findFromCache(const char* data, uint32_t size, const string& ScopedLock lock(key); auto loader = _activeLoaders.head; - auto key = HASH_KEY(data, size); + auto key = HASH_KEY(data); while (loader) { if (loader->type == type && loader->hashkey == key) { @@ -281,7 +281,7 @@ bool LoaderMgr::retrieve(LoadModule* loader) { if (!loader) return false; if (loader->close()) { - { + if (loader->cached()) { ScopedLock lock(key); _activeLoaders.remove(loader); } @@ -300,6 +300,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid) if (auto loader = _findByPath(path)) { if (loader->open(path)) { loader->hashpath = strdup(path.c_str()); + loader->pathcache = true; { ScopedLock lock(key); _activeLoaders.back(loader); @@ -313,6 +314,7 @@ LoadModule* LoaderMgr::loader(const string& path, bool* invalid) if (auto loader = _find(static_cast(i))) { if (loader->open(path)) { loader->hashpath = strdup(path.c_str()); + loader->pathcache = true; { ScopedLock lock(key); _activeLoaders.back(loader); @@ -338,7 +340,7 @@ LoadModule* LoaderMgr::loader(const char* key) auto loader = _activeLoaders.head; while (loader) { - if (loader->hashpath && strstr(loader->hashpath, key)) { + if (loader->pathcache && strstr(loader->hashpath, key)) { ++loader->sharing; return loader; } @@ -350,15 +352,21 @@ LoadModule* LoaderMgr::loader(const char* key) LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy) { - if (auto loader = _findFromCache(data, size, mimeType)) return loader; + //Note that users could use the same data pointer with the different content. + //Thus caching is only valid for shareable. + if (!copy) { + if (auto loader = _findFromCache(data, size, mimeType)) return loader; + } //Try with the given MimeType if (!mimeType.empty()) { if (auto loader = _findByType(mimeType)) { if (loader->open(data, size, copy)) { - loader->hashkey = HASH_KEY(data, size); - ScopedLock lock(key); - _activeLoaders.back(loader); + if (!copy) { + loader->hashkey = HASH_KEY(data); + ScopedLock lock(key); + _activeLoaders.back(loader); + } return loader; } else { TVGLOG("LOADER", "Given mimetype \"%s\" seems incorrect or not supported.", mimeType.c_str()); @@ -371,8 +379,8 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim auto loader = _find(static_cast(i)); if (loader) { if (loader->open(data, size, copy)) { - loader->hashkey = HASH_KEY(data, size); - { + if (!copy) { + loader->hashkey = HASH_KEY(data); ScopedLock lock(key); _activeLoaders.back(loader); } @@ -387,14 +395,18 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const string& mim LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, bool copy) { - //TODO: should we check premultiplied?? - if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader; + //Note that users could use the same data pointer with the different content. + //Thus caching is only valid for shareable. + if (!copy) { + //TODO: should we check premultiplied?? + if (auto loader = _findFromCache((const char*)(data), w * h, "raw")) return loader; + } //function is dedicated for raw images only auto loader = new RawLoader; if (loader->open(data, w, h, copy)) { - loader->hashkey = HASH_KEY((const char*)data, w * h); - { + if (!copy) { + loader->hashkey = HASH_KEY((const char*)data); ScopedLock lock(key); _activeLoaders.back(loader); } diff --git a/thirdparty/thorvg/src/renderer/tvgRender.h b/thirdparty/thorvg/src/renderer/tvgRender.h index 210382efb4f3..a44d41ffdd20 100644 --- a/thirdparty/thorvg/src/renderer/tvgRender.h +++ b/thirdparty/thorvg/src/renderer/tvgRender.h @@ -59,7 +59,7 @@ struct Surface uint32_t w = 0, h = 0; ColorSpace cs = ColorSpace::Unsupported; uint8_t channelSize = 0; - bool premultiplied = 0; //Alpha-premultiplied + bool premultiplied = false; //Alpha-premultiplied Surface() { diff --git a/thirdparty/thorvg/src/renderer/tvgSaver.cpp b/thirdparty/thorvg/src/renderer/tvgSaver.cpp index 11eb24d43790..068b5ee6c3b1 100644 --- a/thirdparty/thorvg/src/renderer/tvgSaver.cpp +++ b/thirdparty/thorvg/src/renderer/tvgSaver.cpp @@ -22,6 +22,7 @@ #include "tvgCommon.h" #include "tvgSaveModule.h" +#include "tvgPaint.h" #ifdef THORVG_TVG_SAVER_SUPPORT #include "tvgTvgSaver.h" @@ -123,7 +124,7 @@ Result Saver::save(std::unique_ptr paint, const string& path, bool compre //Already on saving an other resource. if (pImpl->saveModule) { - delete(p); + if (P(p)->refCnt == 0) delete(p); return Result::InsufficientCondition; } @@ -132,12 +133,12 @@ Result Saver::save(std::unique_ptr paint, const string& path, bool compre pImpl->saveModule = saveModule; return Result::Success; } else { - delete(p); + if (P(p)->refCnt == 0) delete(p); delete(saveModule); return Result::Unknown; } } - delete(p); + if (P(p)->refCnt == 0) delete(p); return Result::NonSupport; } diff --git a/thirdparty/thorvg/src/renderer/tvgShape.cpp b/thirdparty/thorvg/src/renderer/tvgShape.cpp index a3b92532a8de..ab1f378b4743 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.cpp +++ b/thirdparty/thorvg/src/renderer/tvgShape.cpp @@ -26,7 +26,7 @@ /************************************************************************/ /* Internal Class Implementation */ /************************************************************************/ -constexpr auto PATH_KAPPA = 0.552284f; + /************************************************************************/ /* External Class Implementation */ @@ -130,11 +130,11 @@ Result Shape::appendCircle(float cx, float cy, float rx, float ry) noexcept auto ryKappa = ry * PATH_KAPPA; pImpl->grow(6, 13); - pImpl->moveTo(cx, cy - ry); - pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); + pImpl->moveTo(cx + rx, cy); pImpl->cubicTo(cx + rx, cy + ryKappa, cx + rxKappa, cy + ry, cx, cy + ry); pImpl->cubicTo(cx - rxKappa, cy + ry, cx - rx, cy + ryKappa, cx - rx, cy); pImpl->cubicTo(cx - rx, cy - ryKappa, cx - rxKappa, cy - ry, cx, cy - ry); + pImpl->cubicTo(cx + rxKappa, cy - ry, cx + rx, cy - ryKappa, cx + rx, cy); pImpl->close(); return Result::Success; @@ -215,20 +215,20 @@ Result Shape::appendRect(float x, float y, float w, float h, float rx, float ry) pImpl->lineTo(x + w, y + h); pImpl->lineTo(x, y + h); pImpl->close(); - //circle + //rounded rectangle or circle } else { auto hrx = rx * PATH_KAPPA; auto hry = ry * PATH_KAPPA; pImpl->grow(10, 17); - pImpl->moveTo(x + w, y + ry); + pImpl->moveTo(x + rx, y); + pImpl->lineTo(x + w - rx, y); + pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); pImpl->lineTo(x + w, y + h - ry); pImpl->cubicTo(x + w, y + h - ry + hry, x + w - rx + hrx, y + h, x + w - rx, y + h); pImpl->lineTo(x + rx, y + h); pImpl->cubicTo(x + rx - hrx, y + h, x, y + h - ry + hry, x, y + h - ry); pImpl->lineTo(x, y + ry); pImpl->cubicTo(x, y + ry - hry, x + rx - hrx, y, x + rx, y); - pImpl->lineTo(x + w - rx, y); - pImpl->cubicTo(x + w - rx + hrx, y, x + w, y + ry - hry, x + w, y + ry); pImpl->close(); } diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index 1a7a29a9992d..740da55847df 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -106,7 +106,7 @@ struct Shape::Impl { //Path bounding size if (rs.path.pts.count > 0 ) { - auto pts = rs.path.pts.data; + auto pts = rs.path.pts.begin(); Point min = { pts->x, pts->y }; Point max = { pts->x, pts->y }; diff --git a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp index 68a3dbe97a6c..fa7aadd7ac06 100644 --- a/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp +++ b/thirdparty/thorvg/src/renderer/tvgTaskScheduler.cpp @@ -123,14 +123,14 @@ struct TaskSchedulerImpl ~TaskSchedulerImpl() { - for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) { + for (auto tq = taskQueues.begin(); tq < taskQueues.end(); ++tq) { (*tq)->complete(); } - for (auto thread = threads.data; thread < threads.end(); ++thread) { + for (auto thread = threads.begin(); thread < threads.end(); ++thread) { (*thread)->join(); delete(*thread); } - for (auto tq = taskQueues.data; tq < taskQueues.end(); ++tq) { + for (auto tq = taskQueues.begin(); tq < taskQueues.end(); ++tq) { delete(*tq); } } diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 2811a43339fd..3ef2c25878d0 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.12.5 +VERSION=0.12.7 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/