diff --git a/Telegram/SourceFiles/lottie/lottie_animation.cpp b/Telegram/SourceFiles/lottie/lottie_animation.cpp index cee1bf7bb6..d9e3b3f88a 100644 --- a/Telegram/SourceFiles/lottie/lottie_animation.cpp +++ b/Telegram/SourceFiles/lottie/lottie_animation.cpp @@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/algorithm.h" #include "zlib.h" #include "logs.h" +#include "rlottie.h" #include #include @@ -82,14 +83,15 @@ auto Init(QByteArray &&content) << content.size(); return Error::ParseFailed; } - const auto document = JsonDocument(std::move(content)); - if (const auto error = document.error()) { + auto animation = rlottie::Animation::loadFromData( + std::string(content.constData(), content.size()), + std::string()); + if (!animation) { qWarning() - << "Lottie Error: Parse failed with code: " - << error; + << "Lottie Error: Parse failed."; return Error::ParseFailed; } - auto result = std::make_unique(document.root()); + auto result = std::make_unique(std::move(animation)); auto information = result->information(); if (!information.frameRate || information.framesCount <= 0 diff --git a/Telegram/SourceFiles/lottie/lottie_frame_renderer.cpp b/Telegram/SourceFiles/lottie/lottie_frame_renderer.cpp index 5929d302e2..f4118d4ed5 100644 --- a/Telegram/SourceFiles/lottie/lottie_frame_renderer.cpp +++ b/Telegram/SourceFiles/lottie/lottie_frame_renderer.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lottie/lottie_animation.h" #include "rasterrenderer/rasterrenderer.h" #include "logs.h" +#include "rlottie.h" #include #include @@ -23,6 +24,8 @@ namespace Lottie { namespace { constexpr auto kDisplaySkipped = crl::time(-1); +constexpr auto kMaxFrameRate = 120; +constexpr auto kMaxSize = 3096; std::weak_ptr GlobalInstance; @@ -171,21 +174,40 @@ void FrameRendererObject::queueGenerateFrames() { }); } -SharedState::SharedState(const JsonObject &definition) -: _scene(definition) { - if (_scene.isValid()) { +SharedState::SharedState(std::unique_ptr animation) +: _animation(std::move(animation)) { + Expects(_animation != nullptr); + + if (isValid()) { auto cover = QImage(); renderFrame(cover, FrameRequest::NonStrict(), 0); init(std::move(cover)); } } +bool SharedState::isValid() const { + auto width = size_t(0); + auto height = size_t(0); + _animation->size(width, height); + const auto frameRate = int(_animation->frameRate()); + return _animation->totalFrame() > 0 + && frameRate > 0 + && frameRate <= kMaxFrameRate + && width > 0 + && width <= kMaxSize + && height > 0 + && height <= kMaxSize; +} + void SharedState::renderFrame( QImage &image, const FrameRequest &request, int index) { - const auto realSize = QSize(_scene.width(), _scene.height()); - if (realSize.isEmpty() || _scene.endFrame() <= _scene.startFrame()) { + auto width = size_t(0); + auto height = size_t(0); + _animation->size(width, height); + const auto realSize = QSize(width, height); + if (realSize.isEmpty() || !_animation->totalFrame()) { return; } @@ -195,32 +217,19 @@ void SharedState::renderFrame( } image.fill(Qt::transparent); - QPainter p(&image); - p.setRenderHints(QPainter::Antialiasing); - p.setRenderHints(QPainter::SmoothPixmapTransform); - p.setRenderHint(QPainter::TextAntialiasing); - p.setRenderHints(QPainter::HighQualityAntialiasing); - if (realSize != size) { - p.scale( - size.width() / float64(realSize.width()), - size.height() / float64(realSize.height())); - } - - const auto frame = std::clamp( - _scene.startFrame() + index, - _scene.startFrame(), - _scene.endFrame() - 1); - _scene.updateProperties(frame); - - RasterRenderer renderer(&p); - _scene.render(renderer, frame); + auto surface = rlottie::Surface( + reinterpret_cast(image.bits()), + image.width(), + image.height(), + image.bytesPerLine()); + _animation->renderSync(index, surface); } void SharedState::init(QImage cover) { Expects(!initialized()); - _frameRate = _scene.frameRate(); - _framesCount = _scene.endFrame() - _scene.startFrame(); + _frameRate = int(_animation->frameRate()); + _framesCount = int(_animation->totalFrame()); _duration = crl::time(1000) * _framesCount / _frameRate; _frames[0].original = std::move(cover); @@ -319,13 +328,17 @@ not_null SharedState::getFrame(int index) const { } Information SharedState::information() const { - if (!_scene.isValid()) { + if (!isValid()) { return {}; } + auto width = size_t(0); + auto height = size_t(0); + _animation->size(width, height); + auto result = Information(); - result.frameRate = _scene.frameRate(); - result.size = QSize(_scene.width(), _scene.height()); - result.framesCount = _scene.endFrame() - _scene.startFrame(); + result.frameRate = int(_animation->frameRate()); + result.size = QSize(width, height); + result.framesCount = int(_animation->totalFrame()); return result; } @@ -421,6 +434,8 @@ crl::time SharedState::markFrameShown() { Unexpected("Counter value in Lottie::SharedState::markFrameShown."); } +SharedState::~SharedState() = default; + std::shared_ptr FrameRenderer::Instance() { if (auto result = GlobalInstance.lock()) { return result; diff --git a/Telegram/SourceFiles/lottie/lottie_frame_renderer.h b/Telegram/SourceFiles/lottie/lottie_frame_renderer.h index c552559901..34cdc9fe98 100644 --- a/Telegram/SourceFiles/lottie/lottie_frame_renderer.h +++ b/Telegram/SourceFiles/lottie/lottie_frame_renderer.h @@ -10,14 +10,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/basic_types.h" #include "base/weak_ptr.h" #include "lottie/lottie_common.h" -#include "bmscene.h" #include #include #include #include -class BMBase; +namespace rlottie { +class Animation; +} // namespace rlottie + class QImage; namespace Lottie { @@ -41,7 +43,7 @@ QImage PrepareFrameByRequest( class SharedState { public: - explicit SharedState(const JsonObject &definition); + explicit SharedState(std::unique_ptr animation); void start(not_null owner, crl::time now); @@ -56,7 +58,10 @@ public: void renderFrame(QImage &image, const FrameRequest &request, int index); [[nodiscard]] bool renderNextFrame(const FrameRequest &request); + ~SharedState(); + private: + bool isValid() const; void init(QImage cover); void renderNextFrame( not_null frame, @@ -65,7 +70,7 @@ private: [[nodiscard]] not_null getFrame(int index) const; [[nodiscard]] int counter() const; - BMScene _scene; + std::unique_ptr _animation; static constexpr auto kCounterUninitialized = -1; std::atomic _counter = kCounterUninitialized;