From 972c6b7f0a5579dcafd493abdebd8a89e6454d7d Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 5 Oct 2026 16:48:00 +0200 Subject: [PATCH] Raise rlottie shape budget and log truncated animations --- tools/chatgui/rlottie_src/inc/rlottie_capi.h | 5 ++++ .../rlottie_src/src/lottie/lottieitem.cpp | 10 +++---- .../chatgui/rlottie_src/src/vector/vdebug.cpp | 20 ++++++++++++++ tools/chatgui/rlottie_src/src/vector/vdebug.h | 2 ++ tools/chatgui/src/animtimer.cpp | 1 + tools/chatgui/src/lottieicon.cpp | 27 ++++++++++++++++++- tools/chatgui/src/lottieicon.h | 4 +++ 7 files changed, 63 insertions(+), 6 deletions(-) diff --git a/tools/chatgui/rlottie_src/inc/rlottie_capi.h b/tools/chatgui/rlottie_src/inc/rlottie_capi.h index bf91ae41..e7de49de 100644 --- a/tools/chatgui/rlottie_src/inc/rlottie_capi.h +++ b/tools/chatgui/rlottie_src/inc/rlottie_capi.h @@ -48,6 +48,11 @@ typedef enum { typedef struct Lottie_Animation_S Lottie_Animation; +/* Предупреждения встроенной библиотеки доступны и без LOTTIE_LOGGING_SUPPORT. */ +#define RLOTTIE_HAS_WARNING_CALLBACK 1 +typedef void (*Lottie_Warning_Callback)(const char *message); +RLOTTIE_API void lottie_set_warning_callback(Lottie_Warning_Callback callback); + /** * @brief Runs lottie initialization code when rlottie library is loaded * dynamically. diff --git a/tools/chatgui/rlottie_src/src/lottie/lottieitem.cpp b/tools/chatgui/rlottie_src/src/lottie/lottieitem.cpp index 7dc6cfbd..825250ef 100644 --- a/tools/chatgui/rlottie_src/src/lottie/lottieitem.cpp +++ b/tools/chatgui/rlottie_src/src/lottie/lottieitem.cpp @@ -94,7 +94,7 @@ static constexpr size_t kMaxLayerNodes = 100000; // global render-node budget // bounds nested repeaters (repeater whose content contains another // repeater), since every copy at every nesting level draws from the same // shared budget. -static constexpr size_t kMaxShapeContentBudget = 15000; +static constexpr size_t kMaxShapeContentBudget = 150000; static renderer::Layer *createLayerItem(model::Layer *layerData, VArenaAlloc *allocator, int depth, @@ -1059,8 +1059,8 @@ void renderer::Group::addChildren(model::Group *data, VArenaAlloc *allocator, ++it) { size_t cost = contentItemCost(*it); if (cost > contentBudget) { - vWarning << "Max shape content budget (" - << kMaxShapeContentBudget << ") exceeded, dropping content item"; + lottieWarning("Shape content budget exceeded: group=%s item=%s cost=%zu remaining=%zu limit=%zu; dropping item", + data->name(), (*it)->name(), cost, contentBudget, kMaxShapeContentBudget); continue; } contentBudget -= cost; @@ -1590,8 +1590,8 @@ renderer::Repeater::Repeater(model::Repeater *data, VArenaAlloc *allocator, for (int i = 0; i < maxCopies; i++) { if (contentBudget == 0) { - vWarning << "Max shape content budget (" << kMaxShapeContentBudget - << ") exceeded, clamping repeater copies to " << i; + lottieWarning("Shape content budget exceeded: repeater=%s copies=%d requested=%d remaining=%zu limit=%zu", + data->name(), i, maxCopies, contentBudget, kMaxShapeContentBudget); break; } --contentBudget; // charge for this copy's own group wrapper diff --git a/tools/chatgui/rlottie_src/src/vector/vdebug.cpp b/tools/chatgui/rlottie_src/src/vector/vdebug.cpp index 03196ef3..38ab35cc 100644 --- a/tools/chatgui/rlottie_src/src/vector/vdebug.cpp +++ b/tools/chatgui/rlottie_src/src/vector/vdebug.cpp @@ -21,6 +21,26 @@ */ #include "vdebug.h" +#include "rlottie_capi.h" +#include +#include +#include + +static std::atomic warningCallback{nullptr}; + +extern "C" void lottie_set_warning_callback(Lottie_Warning_Callback callback) { + warningCallback.store(callback); +} + +void lottieWarning(const char *format, ...) { + char message[1024]; + va_list args; + va_start(args, format); + std::vsnprintf(message, sizeof(message), format, args); + va_end(args); + if (auto callback = warningCallback.load()) callback(message); + else std::fprintf(stderr, "[WARN] rlottie: %s\n", message); +} #ifdef LOTTIE_LOGGING_SUPPORT diff --git a/tools/chatgui/rlottie_src/src/vector/vdebug.h b/tools/chatgui/rlottie_src/src/vector/vdebug.h index 5b6bef5b..f7630142 100644 --- a/tools/chatgui/rlottie_src/src/vector/vdebug.h +++ b/tools/chatgui/rlottie_src/src/vector/vdebug.h @@ -25,6 +25,8 @@ #include "config.h" +void lottieWarning(const char *format, ...); + #ifdef LOTTIE_LOGGING_SUPPORT #include diff --git a/tools/chatgui/src/animtimer.cpp b/tools/chatgui/src/animtimer.cpp index df008b7d..611fae87 100644 --- a/tools/chatgui/src/animtimer.cpp +++ b/tools/chatgui/src/animtimer.cpp @@ -60,6 +60,7 @@ void AnimTimer::onTimer() { void AnimTimer::logRegisteredIcons() const { for (auto it = m_icons.constBegin(); it != m_icons.constEnd(); ++it) { LottieIcon *icon = it.value(); + icon->logWarnings(); GUI_DEBUG("LottieIcon: path=%s frames=%d size=%dx%d tgsSize=%d valid=%d", qPrintable(it.key()), icon->frameCount(), icon->originalSize().width(), icon->originalSize().height(), diff --git a/tools/chatgui/src/lottieicon.cpp b/tools/chatgui/src/lottieicon.cpp index 36a85d08..67188953 100644 --- a/tools/chatgui/src/lottieicon.cpp +++ b/tools/chatgui/src/lottieicon.cpp @@ -1,8 +1,18 @@ #include "lottieicon.h" +#include "debug_ui.h" #include #include #include +#ifdef RLOTTIE_HAS_WARNING_CALLBACK +static thread_local QStringList *lottieLoadWarnings = nullptr; + +static void logLottieWarning(const char *message) { + if (lottieLoadWarnings) lottieLoadWarnings->append(QString::fromUtf8(message)); + else GUI_WARN("LottieIcon: rlottie: %s", message); +} +#endif + static QByteArray unpackGzip(const QByteArray &data) { if (data.isEmpty()) return {}; z_stream strm = {}; @@ -33,14 +43,25 @@ static QByteArray unpackGzip(const QByteArray &data) { return result; } -LottieIcon::LottieIcon(const QByteArray &tgsData, const QString &key) { +LottieIcon::LottieIcon(const QByteArray &tgsData, const QString &key) : m_key(key) { +#ifdef RLOTTIE_HAS_WARNING_CALLBACK + lottie_set_warning_callback(logLottieWarning); +#endif m_tgsSize = (int)tgsData.size(); QByteArray json = unpackGzip(tgsData); if (json.isEmpty()) return; m_jsonData = json; QByteArray keyUtf8 = key.toUtf8(); +#ifdef RLOTTIE_HAS_WARNING_CALLBACK + // При старте настройки общего журнала применяются после загрузки иконок. + QStringList *previousWarnings = lottieLoadWarnings; + lottieLoadWarnings = &m_loadWarnings; +#endif m_anim = lottie_animation_from_data(m_jsonData.constData(), keyUtf8.constData(), ""); +#ifdef RLOTTIE_HAS_WARNING_CALLBACK + lottieLoadWarnings = previousWarnings; +#endif if (!m_anim) return; lottie_animation_get_size(m_anim, &m_w, &m_h); @@ -54,6 +75,10 @@ LottieIcon::~LottieIcon() { if (m_anim) lottie_animation_destroy(m_anim); } +void LottieIcon::logWarnings() const { + for (const QString &message : m_loadWarnings) GUI_WARN("LottieIcon: path=%s rlottie: %s", qPrintable(m_key), qPrintable(message)); +} + QImage LottieIcon::renderFrame(int frameNum, QSize targetSize) const { if (!m_valid || targetSize.width() <= 0 || targetSize.height() <= 0) return QImage(); diff --git a/tools/chatgui/src/lottieicon.h b/tools/chatgui/src/lottieicon.h index 5be28979..ac5e40cd 100644 --- a/tools/chatgui/src/lottieicon.h +++ b/tools/chatgui/src/lottieicon.h @@ -5,6 +5,7 @@ #include #include #include +#include #include class LottieIcon { @@ -19,6 +20,7 @@ public: int currentFrame() const { return m_currentFrame; } int tgsSize() const { return m_tgsSize; } void setTgsSize(int sz) { m_tgsSize = sz; } + void logWarnings() const; QImage renderFrame(int frameNum, QSize targetSize) const; void advanceFrame() { m_currentFrame = (m_currentFrame + 1) % m_totalFrames; } @@ -32,4 +34,6 @@ private: double m_frameRate = 60.0; size_t m_w = 0, m_h = 0; QByteArray m_jsonData; + QString m_key; + QStringList m_loadWarnings; };