Browse Source

Raise rlottie shape budget and log truncated animations

master
evgeny 6 days ago
parent
commit
972c6b7f0a
  1. 5
      tools/chatgui/rlottie_src/inc/rlottie_capi.h
  2. 10
      tools/chatgui/rlottie_src/src/lottie/lottieitem.cpp
  3. 20
      tools/chatgui/rlottie_src/src/vector/vdebug.cpp
  4. 2
      tools/chatgui/rlottie_src/src/vector/vdebug.h
  5. 1
      tools/chatgui/src/animtimer.cpp
  6. 27
      tools/chatgui/src/lottieicon.cpp
  7. 4
      tools/chatgui/src/lottieicon.h

5
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.

10
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

20
tools/chatgui/rlottie_src/src/vector/vdebug.cpp

@ -21,6 +21,26 @@
*/
#include "vdebug.h"
#include "rlottie_capi.h"
#include <atomic>
#include <cstdarg>
#include <cstdio>
static std::atomic<Lottie_Warning_Callback> 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

2
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 <cstdint>

1
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(),

27
tools/chatgui/src/lottieicon.cpp

@ -1,8 +1,18 @@
#include "lottieicon.h"
#include "debug_ui.h"
#include <rlottie_capi.h>
#include <zlib.h>
#include <cstring>
#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();

4
tools/chatgui/src/lottieicon.h

@ -5,6 +5,7 @@
#include <QImage>
#include <QByteArray>
#include <QSize>
#include <QStringList>
#include <cstdint>
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;
};

Loading…
Cancel
Save