From ad3c6ebb1ea757cd6a53f34938ada49eafc97668 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 19 May 2022 19:05:07 +0400 Subject: [PATCH] Use / cache the same sticker / effect size in preview. --- .../SourceFiles/boxes/sticker_preview_box.cpp | 41 ++++--- .../chat_helpers/stickers_emoji_pack.cpp | 56 ++++++++++ .../chat_helpers/stickers_emoji_pack.h | 12 +++ .../view/history_view_emoji_interactions.cpp | 102 +++++------------- .../view/history_view_emoji_interactions.h | 19 +--- .../view/media/history_view_sticker.cpp | 18 +++- .../history/view/media/history_view_sticker.h | 4 + .../window/window_media_preview.cpp | 37 ++++--- 8 files changed, 164 insertions(+), 125 deletions(-) diff --git a/Telegram/SourceFiles/boxes/sticker_preview_box.cpp b/Telegram/SourceFiles/boxes/sticker_preview_box.cpp index 0f6be3091..35da7eae0 100644 --- a/Telegram/SourceFiles/boxes/sticker_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_preview_box.cpp @@ -7,15 +7,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "boxes/sticker_preview_box.h" +#include "chat_helpers/stickers_lottie.h" +#include "chat_helpers/stickers_emoji_pack.h" #include "data/data_file_origin.h" #include "data/data_document.h" #include "data/data_document_media.h" #include "lang/lang_keys.h" +#include "main/main_session.h" #include "ui/chat/chat_theme.h" #include "ui/layers/generic_box.h" #include "ui/widgets/buttons.h" #include "ui/wrap/padding_wrap.h" #include "lottie/lottie_single_player.h" +#include "history/view/media/history_view_sticker.h" #include "window/window_session_controller.h" #include "styles/style_layers.h" #include "styles/style_chat_helpers.h" @@ -23,7 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace { constexpr auto kPremiumShift = 0.082; -constexpr auto kPremiumMultiplier = 1.5; struct Preload { not_null document; @@ -57,9 +60,10 @@ void PreloadSticker(const std::shared_ptr &media) { }; const auto state = lifetime.make_state(); - const auto lottie = int(size / kPremiumMultiplier); - const auto lottieSize = QSize(lottie, lottie); - const auto effectSize = QSize(size, size); + using namespace HistoryView; + const auto document = media->owner(); + const auto lottieSize = Sticker::Size(document); + const auto effectSize = Sticker::PremiumEffectSize(document); const auto createLottieIfReady = [=] { if (state->lottie) { return; @@ -73,14 +77,17 @@ void PreloadSticker(const std::shared_ptr &media) { } const auto factor = style::DevicePixelRatio(); - state->lottie = std::make_unique( - Lottie::ReadContent(media->bytes(), document->filepath()), - Lottie::FrameRequest{ lottieSize * factor }, - Lottie::Quality::High); - state->effect = std::make_unique( - Lottie::ReadContent(media->videoThumbnailContent(), {}), - Lottie::FrameRequest{ effectSize * factor }, + state->lottie = ChatHelpers::LottiePlayerFromDocument( + media.get(), + nullptr, + ChatHelpers::StickerLottieSize::MessageHistory, + lottieSize * factor, Lottie::Quality::High); + state->effect = document->session().emojiStickersPack().effectPlayer( + document, + media->videoThumbnailContent(), + QString(), + true); const auto update = [=] { raw->update(); }; auto &lifetime = raw->lifetime(); @@ -104,12 +111,12 @@ void PreloadSticker(const std::shared_ptr &media) { const auto frame = state->lottie->frameInfo({ lottieSize * factor }); const auto effect = state->effect->frameInfo( { effectSize * factor }); - const auto framesCount = !frame.image.isNull() - ? state->lottie->framesCount() - : 1; - const auto effectsCount = !effect.image.isNull() - ? state->effect->framesCount() - : 1; + //const auto framesCount = !frame.image.isNull() + // ? state->lottie->framesCount() + // : 1; + //const auto effectsCount = !effect.image.isNull() + // ? state->effect->framesCount() + // : 1; const auto left = effectSize.width() - int(lottieSize.width() * (1. + kPremiumShift)); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp index d663f4290..82846c1f9 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp @@ -20,6 +20,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/core_settings.h" #include "core/application.h" #include "base/call_delayed.h" +#include "chat_helpers/stickers_lottie.h" +#include "history/view/media/history_view_sticker.h" +#include "lottie/lottie_single_player.h" #include "apiwrap.h" #include "styles/style_chat.h" @@ -29,6 +32,8 @@ namespace Stickers { namespace { constexpr auto kRefreshTimeout = 7200 * crl::time(1000); +constexpr auto kEmojiCachesCount = 4; +constexpr auto kPremiumCachesCount = 8; [[nodiscard]] std::optional IndexFromEmoticon(const QString &emoticon) { if (emoticon.size() < 2) { @@ -201,6 +206,57 @@ auto EmojiPack::animationsForEmoji(EmojiPtr emoji) const return (i != end(_animations)) ? i->second : empty; } +std::unique_ptr EmojiPack::effectPlayer( + not_null document, + QByteArray data, + QString filepath, + bool premium) { + // Shortened copy from stickers_lottie module. + const auto baseKey = document->bigFileBaseCacheKey(); + const auto tag = uint8(0); + const auto keyShift = ((tag << 4) & 0xF0) + | (uint8(ChatHelpers::StickerLottieSize::EmojiInteraction) & 0x0F); + const auto key = Storage::Cache::Key{ + baseKey.high, + baseKey.low + keyShift + }; + const auto get = [=](int i, FnMut handler) { + document->owner().cacheBigFile().get( + { key.high, key.low + i }, + std::move(handler)); + }; + const auto weak = base::make_weak(&document->session()); + const auto put = [=](int i, QByteArray &&cached) { + crl::on_main(weak, [=, data = std::move(cached)]() mutable { + weak->data().cacheBigFile().put( + { key.high, key.low + i }, + std::move(data)); + }); + }; + const auto size = premium + ? HistoryView::Sticker::PremiumEffectSize(document) + : HistoryView::Sticker::EmojiEffectSize(); + const auto request = Lottie::FrameRequest{ + size * style::DevicePixelRatio(), + }; + auto &weakProvider = _sharedProviders[document]; + auto shared = [&] { + if (const auto result = weakProvider.lock()) { + return result; + } + const auto result = Lottie::SinglePlayer::SharedProvider( + premium ? kPremiumCachesCount : kEmojiCachesCount, + get, + put, + Lottie::ReadContent(data, filepath), + request, + Lottie::Quality::High); + weakProvider = result; + return result; + }(); + return std::make_unique(std::move(shared), request); +} + void EmojiPack::refresh() { if (_requestId) { return; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h index 8f62a5d2a..3170ca110 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h @@ -21,6 +21,8 @@ class Session; } // namespace Main namespace Lottie { +class SinglePlayer; +class FrameProvider; struct ColorReplacements; } // namespace Lottie @@ -70,6 +72,12 @@ public: [[nodiscard]] auto animationsForEmoji(EmojiPtr emoji) const -> const base::flat_map> &; + [[nodiscard]] std::unique_ptr effectPlayer( + not_null document, + QByteArray data, + QString filepath, + bool premium); + private: class ImageLoader; @@ -103,6 +111,10 @@ private: base::flat_map>> _animations; mtpRequestId _animationsRequestId = 0; + base::flat_map< + not_null, + std::weak_ptr> _sharedProviders; + rpl::lifetime _lifetime; }; diff --git a/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp b/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp index afd67ae76..58912f32f 100644 --- a/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp +++ b/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp @@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/view/history_view_element.h" #include "history/view/media/history_view_sticker.h" #include "history/history.h" +#include "chat_helpers/stickers_emoji_pack.h" #include "chat_helpers/emoji_interactions.h" #include "chat_helpers/stickers_lottie.h" #include "main/main_session.h" @@ -24,11 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { -constexpr auto kEmojiMultiplier = 3; constexpr auto kPremiumShift = 0.082; -constexpr auto kPremiumMultiplier = 1.5; -constexpr auto kEmojiCachesCount = 4; -constexpr auto kPremiumCachesCount = 8; constexpr auto kMaxPlays = 5; constexpr auto kMaxPlaysWithSmallDelay = 3; constexpr auto kSmallDelay = crl::time(200); @@ -59,9 +56,6 @@ EmojiInteractions::EmojiInteractions( ranges::remove(_delayed, view, &Delayed::view), end(_delayed)); }, _lifetime); - - _emojiSize = Sticker::EmojiSize(); - _premiumSize = Sticker::Size(); } EmojiInteractions::~EmojiInteractions() { @@ -172,9 +166,16 @@ void EmojiInteractions::play( return; } - auto lottie = preparePlayer(document, data, filepath, premium); + auto lottie = document->session().emojiStickersPack().effectPlayer( + document, + data, + filepath, + premium); - const auto shift = premium ? QPoint() : GenerateRandomShift(_emojiSize); + const auto inner = premium + ? HistoryView::Sticker::Size(document) + : HistoryView::Sticker::EmojiSize(); + const auto shift = premium ? QPoint() : GenerateRandomShift(inner); const auto raw = lottie.get(); lottie->updates( ) | rpl::start_with_next([=](Lottie::Update update) { @@ -183,9 +184,7 @@ void EmojiInteractions::play( const auto i = ranges::find(_plays, raw, [](const Play &p) { return p.lottie.get(); }); - const auto rect = computeRect( - i->view, - i->premium).translated(shift); + const auto rect = computeRect(*i).translated(shift); if (rect.y() + rect.height() >= _visibleTop && rect.y() <= _visibleBottom) { _updateRequests.fire_copy(rect); @@ -199,6 +198,10 @@ void EmojiInteractions::play( .view = view, .lottie = std::move(lottie), .shift = shift, + .inner = inner, + .outer = (premium + ? HistoryView::Sticker::PremiumEffectSize(document) + : HistoryView::Sticker::EmojiEffectSize()), .premium = premium, }); if (incoming) { @@ -211,60 +214,6 @@ void EmojiInteractions::play( } } -QSize EmojiInteractions::sizeFor(bool premium) const { - return premium - ? (_premiumSize * kPremiumMultiplier) - : (_emojiSize * kEmojiMultiplier); -} - -std::unique_ptr EmojiInteractions::preparePlayer( - not_null document, - QByteArray data, - QString filepath, - bool premium) { - // Shortened copy from stickers_lottie module. - const auto baseKey = document->bigFileBaseCacheKey(); - const auto tag = uint8(0); - const auto keyShift = ((tag << 4) & 0xF0) - | (uint8(ChatHelpers::StickerLottieSize::EmojiInteraction) & 0x0F); - const auto key = Storage::Cache::Key{ - baseKey.high, - baseKey.low + keyShift - }; - const auto get = [=](int i, FnMut handler) { - document->owner().cacheBigFile().get( - { key.high, key.low + i }, - std::move(handler)); - }; - const auto weak = base::make_weak(&document->session()); - const auto put = [=](int i, QByteArray &&cached) { - crl::on_main(weak, [=, data = std::move(cached)]() mutable { - weak->data().cacheBigFile().put( - { key.high, key.low + i }, - std::move(data)); - }); - }; - const auto request = Lottie::FrameRequest{ - sizeFor(premium) * style::DevicePixelRatio(), - }; - auto &weakProvider = _sharedProviders[document]; - auto shared = [&] { - if (const auto result = weakProvider.lock()) { - return result; - } - const auto result = Lottie::SinglePlayer::SharedProvider( - premium ? kPremiumCachesCount : kEmojiCachesCount, - get, - put, - Lottie::ReadContent(data, filepath), - request, - Lottie::Quality::High); - weakProvider = result; - return result; - }(); - return std::make_unique(std::move(shared), request); -} - void EmojiInteractions::visibleAreaUpdated( int visibleTop, int visibleBottom) { @@ -272,14 +221,13 @@ void EmojiInteractions::visibleAreaUpdated( _visibleBottom = visibleBottom; } -QRect EmojiInteractions::computeRect( - not_null view, - bool premium) const { +QRect EmojiInteractions::computeRect(const Play &play) const { + const auto view = play.view; const auto fullWidth = view->width(); - const auto sticker = premium ? _premiumSize : _emojiSize; - const auto size = sizeFor(premium); - const auto shift = premium - ? int(_premiumSize.width() * kPremiumShift) + const auto sticker = play.inner; + const auto size = play.outer; + const auto shift = play.premium + ? int(sticker.width() * kPremiumShift) : (size.width() / 40); const auto inner = view->innerGeometry(); const auto rightAligned = view->hasOutLayout() @@ -292,7 +240,7 @@ QRect EmojiInteractions::computeRect( return QRect(); } const auto top = viewTop + (sticker.height() - size.height()) / 2; - return QRect(QPoint(left, top), size); + return QRect(QPoint(left, top), size).translated(play.shift); } void EmojiInteractions::paint(QPainter &p) { @@ -302,7 +250,7 @@ void EmojiInteractions::paint(QPainter &p) { continue; } auto request = Lottie::FrameRequest(); - request.box = sizeFor(play.premium) * factor; + request.box = play.outer * factor; const auto rightAligned = play.view->hasOutLayout() && !play.view->delegate()->elementIsChatWide(); if (!rightAligned) { @@ -315,9 +263,7 @@ void EmojiInteractions::paint(QPainter &p) { play.framesCount = information.framesCount; play.frameRate = information.frameRate; } - const auto rect = computeRect( - play.view, - play.premium).translated(play.shift); + const auto rect = computeRect(play); if (play.started && !play.frame) { play.finished = true; _updateRequests.fire_copy(rect); diff --git a/Telegram/SourceFiles/history/view/history_view_emoji_interactions.h b/Telegram/SourceFiles/history/view/history_view_emoji_interactions.h index 9af23d5e2..4214af4be 100644 --- a/Telegram/SourceFiles/history/view/history_view_emoji_interactions.h +++ b/Telegram/SourceFiles/history/view/history_view_emoji_interactions.h @@ -17,7 +17,6 @@ struct EmojiInteractionPlayRequest; namespace Lottie { class SinglePlayer; -class FrameProvider; } // namespace Lottie namespace Main { @@ -53,6 +52,8 @@ private: not_null view; std::unique_ptr lottie; QPoint shift; + QSize inner; + QSize outer; int frame = 0; int framesCount = 0; int frameRate = 0; @@ -68,9 +69,7 @@ private: bool incoming = false; }; - [[nodiscard]] QRect computeRect( - not_null view, - bool premium) const; + [[nodiscard]] QRect computeRect(const Play &play) const; void play( QString emoticon, @@ -87,28 +86,16 @@ private: bool premium); void checkDelayed(); - [[nodiscard]] QSize sizeFor(bool premium) const; - [[nodiscard]] std::unique_ptr preparePlayer( - not_null document, - QByteArray data, - QString filepath, - bool premium); - const not_null _session; const Fn)> _itemTop; int _visibleTop = 0; int _visibleBottom = 0; - QSize _emojiSize; - QSize _premiumSize; std::vector _plays; std::vector _delayed; rpl::event_stream _updateRequests; rpl::event_stream _playStarted; - base::flat_map< - not_null, - std::weak_ptr> _sharedProviders; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp index ea96b68c4..be086e6ef 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp @@ -39,6 +39,8 @@ namespace { constexpr auto kMaxSizeFixed = 512; constexpr auto kMaxEmojiSizeFixed = 256; +constexpr auto kPremiumMultiplier = 1.5; +constexpr auto kEmojiMultiplier = 3; [[nodiscard]] QImage CacheDiceImage( const QString &emoji, @@ -104,12 +106,12 @@ bool Sticker::isEmojiSticker() const { void Sticker::initSize() { if (isEmojiSticker() || _diceIndex >= 0) { - _size = Sticker::EmojiSize(); + _size = EmojiSize(); if (_diceIndex > 0) { [[maybe_unused]] bool result = readyToDrawLottie(); } } else { - _size = DownscaledSize(_data->dimensions, Sticker::Size()); + _size = Size(_data); } } @@ -145,6 +147,18 @@ QSize Sticker::Size() { return { side, side }; } +QSize Sticker::Size(not_null document) { + return DownscaledSize(document->dimensions, Size()); +} + +QSize Sticker::PremiumEffectSize(not_null document) { + return Size(document) * kPremiumMultiplier; +} + +QSize Sticker::EmojiEffectSize() { + return EmojiSize() * kEmojiMultiplier; +} + QSize Sticker::EmojiSize() { const auto side = std::min(st::maxAnimatedEmojiSize, kMaxEmojiSizeFixed); return { side, side }; diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.h b/Telegram/SourceFiles/history/view/media/history_view_sticker.h index 04e5e1251..c0bcd67be 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.h +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.h @@ -77,6 +77,10 @@ public: [[nodiscard]] bool readyToDrawLottie(); [[nodiscard]] static QSize Size(); + [[nodiscard]] static QSize Size(not_null document); + [[nodiscard]] static QSize PremiumEffectSize( + not_null document); + [[nodiscard]] static QSize EmojiEffectSize(); [[nodiscard]] static QSize EmojiSize(); [[nodiscard]] static ClickHandlerPtr ShowSetHandler( not_null document); diff --git a/Telegram/SourceFiles/window/window_media_preview.cpp b/Telegram/SourceFiles/window/window_media_preview.cpp index 36d3a9339..caf896638 100644 --- a/Telegram/SourceFiles/window/window_media_preview.cpp +++ b/Telegram/SourceFiles/window/window_media_preview.cpp @@ -7,12 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "window/window_media_preview.h" +#include "chat_helpers/stickers_lottie.h" +#include "chat_helpers/stickers_emoji_pack.h" #include "data/data_photo.h" #include "data/data_photo_media.h" #include "data/data_document.h" #include "data/data_document_media.h" #include "data/data_session.h" #include "data/stickers/data_stickers.h" +#include "history/view/media/history_view_sticker.h" #include "ui/image/image.h" #include "ui/emoji_config.h" #include "lottie/lottie_single_player.h" @@ -72,10 +75,10 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) { : Lottie::Animation::FrameInfo(); const auto image = frame.image; const auto effectImage = effect.image; - const auto framesCount = !image.isNull() ? _lottie->framesCount() : 1; - const auto effectsCount = !effectImage.isNull() - ? _effect->framesCount() - : 1; + //const auto framesCount = !image.isNull() ? _lottie->framesCount() : 1; + //const auto effectsCount = !effectImage.isNull() + // ? _effect->framesCount() + // : 1; const auto pixmap = image.isNull() ? currentImage() : QPixmap(); const auto size = image.isNull() ? pixmap.size() : image.size(); int w = size.width() / factor, h = size.height() / factor; @@ -309,15 +312,25 @@ void MediaPreviewWidget::setupLottie() { Expects(_document != nullptr); const auto factor = cIntRetinaFactor(); - const auto size = currentDimensions(); - _lottie = std::make_unique( - Lottie::ReadContent(_documentMedia->bytes(), _document->filepath()), - Lottie::FrameRequest{ size * factor }, - Lottie::Quality::High); if (_document->isPremiumSticker()) { - _effect = std::make_unique( - Lottie::ReadContent(_documentMedia->videoThumbnailContent(), {}), - Lottie::FrameRequest{ size * kPremiumMultiplier * factor }, + const auto size = HistoryView::Sticker::Size(_document); + _cachedSize = size; + _lottie = ChatHelpers::LottiePlayerFromDocument( + _documentMedia.get(), + nullptr, + ChatHelpers::StickerLottieSize::MessageHistory, + size * factor, + Lottie::Quality::High); + _effect = _document->session().emojiStickersPack().effectPlayer( + _document, + _documentMedia->videoThumbnailContent(), + QString(), + true); + } else { + const auto size = currentDimensions(); + _lottie = std::make_unique( + Lottie::ReadContent(_documentMedia->bytes(), _document->filepath()), + Lottie::FrameRequest{ size * factor }, Lottie::Quality::High); }