diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index a4ca43419..50ab929f5 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -380,7 +380,7 @@ std::unique_ptr CustomEmojiManager::create( documentId, std::make_unique(Loading{ factory(), - Ui::CustomEmoji::Preview() + prepareNonExactPreview(documentId, tag) }, std::move(repaint))).first; } return std::make_unique( @@ -388,6 +388,27 @@ std::unique_ptr CustomEmojiManager::create( std::move(update)); } +Ui::CustomEmoji::Preview CustomEmojiManager::prepareNonExactPreview( + DocumentId documentId, + SizeTag tag) const { + const auto &other = _instances[1 - SizeIndex(tag)]; + const auto j = other.find(documentId); + if (j == end(other)) { + return {}; + } else if (const auto nonExact = j->second->imagePreview()) { + const auto size = SizeFromTag(tag); + return { + nonExact.image().scaled( + size, + size, + Qt::IgnoreAspectRatio, + Qt::SmoothTransformation), + false, + }; + } + return {}; +} + std::unique_ptr CustomEmojiManager::create( QStringView data, Fn update, diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h index a203fb62e..f4a1c6696 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.h +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.h @@ -78,6 +78,9 @@ private: void invokeRepaints(); void requestSetFor(not_null document); + [[nodiscard]] Ui::CustomEmoji::Preview prepareNonExactPreview( + DocumentId documentId, + SizeTag tag) const; template [[nodiscard]] std::unique_ptr create( DocumentId documentId, diff --git a/Telegram/SourceFiles/ui/text/custom_emoji_instance.cpp b/Telegram/SourceFiles/ui/text/custom_emoji_instance.cpp index f646f59ee..e96da5ebd 100644 --- a/Telegram/SourceFiles/ui/text/custom_emoji_instance.cpp +++ b/Telegram/SourceFiles/ui/text/custom_emoji_instance.cpp @@ -37,22 +37,38 @@ Preview::Preview(QPainterPath path, float64 scale) : _data(ScaledPath{ std::move(path), scale }) { } -Preview::Preview(QImage image) : _data(std::move(image)) { +Preview::Preview(QImage image, bool exact) +: _data(Image{ .data = std::move(image), .exact = exact }) { } void Preview::paint(QPainter &p, int x, int y, const QColor &preview) { if (const auto path = std::get_if(&_data)) { paintPath(p, x, y, preview, *path); - } else if (const auto image = std::get_if(&_data)) { + } else if (const auto image = std::get_if(&_data)) { + const auto &data = image->data; const auto factor = style::DevicePixelRatio(); - const auto width = image->width() / factor; - const auto height = image->height() / factor; - p.drawImage(QRect(x, y, width, height), *image); + const auto width = data.width() / factor; + const auto height = data.height() / factor; + p.drawImage(QRect(x, y, width, height), data); } } -bool Preview::image() const { - return v::is(_data); +bool Preview::isImage() const { + return v::is(_data); +} + +bool Preview::isExactImage() const { + if (const auto image = std::get_if(&_data)) { + return image->exact; + } + return false; +} + +QImage Preview::image() const { + if (const auto image = std::get_if(&_data)) { + return image->data; + } + return QImage(); } void Preview::paintPath( @@ -190,7 +206,7 @@ Preview Cache::makePreview() const { Expects(_frames > 0); const auto first = frame(0); - return { first.image->copy(first.source) }; + return { first.image->copy(first.source), true }; } void Cache::reserve(int frames) { @@ -349,8 +365,12 @@ PaintFrameResult Cached::paint(QPainter &p, int x, int y, crl::time now) { return _cache.paintCurrentFrame(p, x, y, now); } +Preview Cached::makePreview() const { + return _cache.makePreview(); +} + Loading Cached::unload() { - return Loading(_unloader(), _cache.makePreview()); + return Loading(_unloader(), makePreview()); } Renderer::Renderer(RendererDescriptor &&descriptor) @@ -516,6 +536,10 @@ void Loading::paint(QPainter &p, int x, int y, const QColor &preview) { _preview.paint(p, x, y, preview); } +Preview Loading::imagePreview() const { + return _preview.isImage() ? _preview : Preview(); +} + void Loading::cancel() { _loader->cancel(); invalidate_weak_ptrs(this); @@ -564,7 +588,7 @@ void Instance::paint( if (!result.painted) { caching->preview.paint(p, x, y, preview); } else { - if (!caching->preview.image()) { + if (!caching->preview.isExactImage()) { caching->preview = caching->renderer->makePreview(); } if (result.next > now) { @@ -582,6 +606,17 @@ void Instance::paint( } } +Preview Instance::imagePreview() const { + if (const auto loading = std::get_if(&_state)) { + return loading->imagePreview(); + } else if (const auto caching = std::get_if(&_state)) { + return caching->preview.isImage() ? caching->preview : Preview(); + } else if (const auto cached = std::get_if(&_state)) { + return cached->makePreview(); + } + return {}; +} + void Instance::repaint() { for (const auto &object : _usage) { object->repaint(); diff --git a/Telegram/SourceFiles/ui/text/custom_emoji_instance.h b/Telegram/SourceFiles/ui/text/custom_emoji_instance.h index 5722f0d22..5f840cbd0 100644 --- a/Telegram/SourceFiles/ui/text/custom_emoji_instance.h +++ b/Telegram/SourceFiles/ui/text/custom_emoji_instance.h @@ -24,11 +24,13 @@ namespace Ui::CustomEmoji { class Preview final { public: Preview() = default; - Preview(QImage image); + Preview(QImage image, bool exact); Preview(QPainterPath path, float64 scale); void paint(QPainter &p, int x, int y, const QColor &preview); - [[nodiscard]] bool image() const; + [[nodiscard]] bool isImage() const; + [[nodiscard]] bool isExactImage() const; + [[nodiscard]] QImage image() const; [[nodiscard]] explicit operator bool() const { return !v::is_null(_data); @@ -39,6 +41,10 @@ private: QPainterPath path; float64 scale = 1.; }; + struct Image { + QImage data; + bool exact = false; + }; void paintPath( QPainter &p, @@ -47,7 +53,7 @@ private: const QColor &preview, const ScaledPath &path); - std::variant _data; + std::variant _data; }; @@ -116,7 +122,7 @@ public: Cache cache); [[nodiscard]] QString entityData() const; - + [[nodiscard]] Preview makePreview() const; PaintFrameResult paint(QPainter &p, int x, int y, crl::time now); [[nodiscard]] Loading unload(); @@ -194,6 +200,7 @@ public: void load(Fn done); [[nodiscard]] bool loading() const; void paint(QPainter &p, int x, int y, const QColor &preview); + [[nodiscard]] Preview imagePreview() const; void cancel(); private: @@ -224,6 +231,7 @@ public: crl::time now, const QColor &preview, bool paused); + [[nodiscard]] Preview imagePreview() const; void incrementUsage(not_null object); void decrementUsage(not_null object);