From 0e11d858e8e407d0b26f254772e7f6820c0302a7 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sun, 26 Jul 2026 15:18:59 +0300 Subject: [PATCH] chatgui: fix all animations showing the same TGS (rlottie model cache key collision) lottie_animation_from_data uses 'key' as a cache key for parsed models. All LottieIcon instances were created with key="", causing rlottie's model cache to return the first loaded animation for all subsequent requests. Only visible on Windows where rlottie cache is enabled by default. Fix: pass unique animPath as key to each LottieIcon constructor. Also replaced fprintf(stderr) diag with GUI_INFO logging via AnimTimer::logRegisteredIcons() in debug_ui.h. --- tools/chatgui/src/animtimer.cpp | 12 +++++++++++- tools/chatgui/src/animtimer.h | 1 + tools/chatgui/src/emojipanel.cpp | 3 --- tools/chatgui/src/lottieicon.cpp | 13 ++++--------- tools/chatgui/src/lottieicon.h | 5 ++++- tools/chatgui/src/mainwindow.cpp | 2 ++ tools/chatgui/src/messagelist.cpp | 9 +-------- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/tools/chatgui/src/animtimer.cpp b/tools/chatgui/src/animtimer.cpp index 67559e25..1cca9184 100644 --- a/tools/chatgui/src/animtimer.cpp +++ b/tools/chatgui/src/animtimer.cpp @@ -1,6 +1,6 @@ #include "animtimer.h" #include "lottieicon.h" -#include "../../lib/debug_config.h" +#include "debug_ui.h" AnimTimer::AnimTimer() { m_timer.setInterval(33); @@ -49,3 +49,13 @@ void AnimTimer::onTimer() { icon->advanceFrame(); emit ticked(); } + +void AnimTimer::logRegisteredIcons() const { + for (auto it = m_icons.constBegin(); it != m_icons.constEnd(); ++it) { + LottieIcon *icon = it.value(); + GUI_INFO("LottieIcon: path=%s frames=%d size=%dx%d tgsSize=%d valid=%d", + qPrintable(it.key()), icon->frameCount(), + icon->originalSize().width(), icon->originalSize().height(), + icon->tgsSize(), (int)icon->isValid()); + } +} diff --git a/tools/chatgui/src/animtimer.h b/tools/chatgui/src/animtimer.h index 4cdb53f0..913a44ac 100644 --- a/tools/chatgui/src/animtimer.h +++ b/tools/chatgui/src/animtimer.h @@ -14,6 +14,7 @@ public: void registerIcon(const QString &key, LottieIcon *icon); void unregisterIcon(const QString &key); LottieIcon *icon(const QString &key) const; + void logRegisteredIcons() const; void activate(); void deactivate(); diff --git a/tools/chatgui/src/emojipanel.cpp b/tools/chatgui/src/emojipanel.cpp index 48927f4e..01eeed96 100644 --- a/tools/chatgui/src/emojipanel.cpp +++ b/tools/chatgui/src/emojipanel.cpp @@ -3,7 +3,6 @@ #include "emojitabbar.h" #include "animtimer.h" #include "lottieicon.h" -#include #include #include #include @@ -35,8 +34,6 @@ public: if (data.type == EmojiType::Animation) { setMouseTracking(true); m_icon = AnimTimer::instance()->icon(data.animPath); - fprintf(stderr, "[DIAG EmojiBtn] btn=%p path=%s m_icon=%p\n", - (void*)this, qPrintable(data.animPath), (void*)m_icon); m_timer.setInterval(33); connect(&m_timer, &QTimer::timeout, this, [this]() { if (m_icon && m_icon->isValid()) { diff --git a/tools/chatgui/src/lottieicon.cpp b/tools/chatgui/src/lottieicon.cpp index d0056b40..36a85d08 100644 --- a/tools/chatgui/src/lottieicon.cpp +++ b/tools/chatgui/src/lottieicon.cpp @@ -2,7 +2,6 @@ #include #include #include -#include static QByteArray unpackGzip(const QByteArray &data) { if (data.isEmpty()) return {}; @@ -34,23 +33,19 @@ static QByteArray unpackGzip(const QByteArray &data) { return result; } -LottieIcon::LottieIcon(const QByteArray &tgsData) { +LottieIcon::LottieIcon(const QByteArray &tgsData, const QString &key) { + m_tgsSize = (int)tgsData.size(); QByteArray json = unpackGzip(tgsData); - fprintf(stderr, "[DIAG LottieIcon] this=%p tgsSize=%d jsonSize=%d jsonEmpty=%d\n", - (void*)this, (int)tgsData.size(), (int)json.size(), (int)json.isEmpty()); if (json.isEmpty()) return; m_jsonData = json; - m_anim = lottie_animation_from_data(m_jsonData.constData(), "", ""); - fprintf(stderr, "[DIAG LottieIcon] this=%p m_anim=%p jsonHead=%.60s\n", - (void*)this, (void*)m_anim, m_jsonData.constData()); + QByteArray keyUtf8 = key.toUtf8(); + m_anim = lottie_animation_from_data(m_jsonData.constData(), keyUtf8.constData(), ""); if (!m_anim) return; lottie_animation_get_size(m_anim, &m_w, &m_h); m_totalFrames = (int)lottie_animation_get_totalframe(m_anim); m_frameRate = lottie_animation_get_framerate(m_anim); - fprintf(stderr, "[DIAG LottieIcon] this=%p frames=%d size=%zux%zu\n", - (void*)this, m_totalFrames, m_w, m_h); if (m_totalFrames <= 0) m_totalFrames = 1; m_valid = true; } diff --git a/tools/chatgui/src/lottieicon.h b/tools/chatgui/src/lottieicon.h index 6ab858e5..a167741f 100644 --- a/tools/chatgui/src/lottieicon.h +++ b/tools/chatgui/src/lottieicon.h @@ -7,7 +7,7 @@ class LottieIcon { public: - explicit LottieIcon(const QByteArray &tgsData); + explicit LottieIcon(const QByteArray &tgsData, const QString &key); ~LottieIcon(); bool isValid() const { return m_valid; } @@ -15,6 +15,8 @@ public: int frameCount() const { return m_totalFrames; } double frameRate() const { return m_frameRate; } int currentFrame() const { return m_currentFrame; } + int tgsSize() const { return m_tgsSize; } + void setTgsSize(int sz) { m_tgsSize = sz; } QImage renderFrame(int frameNum, QSize targetSize) const; void advanceFrame() { m_currentFrame = (m_currentFrame + 1) % m_totalFrames; } @@ -24,6 +26,7 @@ private: struct Lottie_Animation_S *m_anim = nullptr; int m_currentFrame = 0; int m_totalFrames = 0; + int m_tgsSize = 0; double m_frameRate = 60.0; size_t m_w = 0, m_h = 0; QByteArray m_jsonData; diff --git a/tools/chatgui/src/mainwindow.cpp b/tools/chatgui/src/mainwindow.cpp index 1e770188..1320cf7c 100644 --- a/tools/chatgui/src/mainwindow.cpp +++ b/tools/chatgui/src/mainwindow.cpp @@ -143,6 +143,8 @@ void MainWindow::setupNode() { if (!m_node->start(m_cfgPath)) qWarning("Failed to start UtunNode"); + else + AnimTimer::instance()->logRegisteredIcons(); } void MainWindow::setupMessaging() { diff --git a/tools/chatgui/src/messagelist.cpp b/tools/chatgui/src/messagelist.cpp index 44d38225..46170866 100644 --- a/tools/chatgui/src/messagelist.cpp +++ b/tools/chatgui/src/messagelist.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -106,17 +105,11 @@ MessageList::MessageList(DbManager* db, QWidget *parent) QFile f(e.animPath); if (f.open(QIODevice::ReadOnly)) { QByteArray raw = f.readAll(); - auto icon = std::make_unique(raw); - fprintf(stderr, "[DIAG register] path=%s fileOpen=1 rawSize=%d iconPtr=%p iconValid=%d\n", - qPrintable(e.animPath), (int)raw.size(), - (void*)icon.get(), (int)icon->isValid()); + auto icon = std::make_unique(raw, e.animPath); if (icon->isValid()) { AnimTimer::instance()->registerIcon(e.animPath, icon.get()); s_icons.push_back(std::move(icon)); } - } else { - fprintf(stderr, "[DIAG register] path=%s fileOpen=0\n", - qPrintable(e.animPath)); } } }