diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp index 03a3b171c..4706014c5 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.cpp @@ -28,7 +28,7 @@ public: crl::weak_on_queue weak, int id); - [[nodiscard]] QImage prepare(const IsolatedEmoji &emoji); + [[nodiscard]] QImage prepare(EmojiPtr emoji); void switchTo(int id); private: @@ -44,16 +44,11 @@ namespace { constexpr auto kRefreshTimeout = TimeId(7200); constexpr auto kUnloadTimeout = 86400 * crl::time(1000); -[[nodiscard]] QSize CalculateSize(const IsolatedEmoji &emoji) { - using namespace rpl::mappers; - +[[nodiscard]] QSize SingleSize() { const auto single = st::largeEmojiSize; - const auto skip = st::largeEmojiSkip; const auto outline = st::largeEmojiOutline; - const auto count = ranges::count_if(emoji.items, _1 != nullptr); - const auto items = single * count + skip * (count - 1); return QSize( - 2 * outline + items, + 2 * outline + single, 2 * outline + single ) * cIntRetinaFactor(); } @@ -61,7 +56,7 @@ constexpr auto kUnloadTimeout = 86400 * crl::time(1000); class ImageSource : public Images::Source { public: explicit ImageSource( - const IsolatedEmoji &emoji, + EmojiPtr emoji, not_null*> loader); void load(Data::FileOrigin origin) override; @@ -100,7 +95,7 @@ private: // While HistoryView::Element-s are almost never destroyed // we make loading of the image lazy. not_null*> _loader; - IsolatedEmoji _emoji; + EmojiPtr _emoji = nullptr; QImage _data; QByteArray _format; QByteArray _bytes; @@ -110,11 +105,11 @@ private: }; ImageSource::ImageSource( - const IsolatedEmoji &emoji, + EmojiPtr emoji, not_null*> loader) : _loader(loader) , _emoji(emoji) -, _size(CalculateSize(emoji)) { +, _size(SingleSize()) { } void ImageSource::load(Data::FileOrigin origin) { @@ -256,31 +251,54 @@ EmojiImageLoader::EmojiImageLoader( , _unloadTimer(_weak.runner(), [=] { _images->clear(); }) { } -QImage EmojiImageLoader::prepare(const IsolatedEmoji &emoji) { +QImage EmojiImageLoader::prepare(EmojiPtr emoji) { Expects(_images.has_value()); _images->ensureLoaded(); - auto result = QImage( - CalculateSize(emoji), - QImage::Format_ARGB32_Premultiplied); const auto factor = cIntRetinaFactor(); + const auto side = st::largeEmojiSize + 2 * st::largeEmojiOutline; + auto tinted = QImage( + QSize(st::largeEmojiSize, st::largeEmojiSize) * factor, + QImage::Format_ARGB32_Premultiplied); + tinted.fill(Qt::white); + { + QPainter p(&tinted); + p.setCompositionMode(QPainter::CompositionMode_DestinationIn); + _images->draw( + p, + emoji, + st::largeEmojiSize * factor, + 0, + 0); + } + auto result = QImage( + QSize(side, side) * factor, + QImage::Format_ARGB32_Premultiplied); result.fill(Qt::transparent); { QPainter p(&result); - auto x = st::largeEmojiOutline; - const auto y = st::largeEmojiOutline; - for (const auto &single : emoji.items) { - if (!single) { - break; + const auto delta = st::largeEmojiOutline * factor; + const auto shifts = std::array{ { + { -1, -1 }, + { 0, -1 }, + { 1, -1 }, + { -1, 0 }, + { 1, 0 }, + { -1, 1 }, + { 0, 1 }, + { 1, 1 }, + } }; + for (const auto &shift : shifts) { + for (auto i = 0; i != delta; ++i) { + p.drawImage(QPoint(delta, delta) + shift * (i + 1), tinted); } - _images->draw( - p, - single, - st::largeEmojiSize * factor, - x * factor, - y * factor); - x += st::largeEmojiSize + st::largeEmojiSkip; } + _images->draw( + p, + emoji, + st::largeEmojiSize * factor, + delta, + delta); } _unloadTimer.callOnce(kUnloadTimeout); return result; @@ -356,7 +374,7 @@ DocumentData *EmojiPack::stickerForEmoji(const IsolatedEmoji &emoji) { return (i != end(_map)) ? i->second.get() : nullptr; } -std::shared_ptr EmojiPack::image(const IsolatedEmoji &emoji) { +std::shared_ptr EmojiPack::image(EmojiPtr emoji) { const auto i = _images.emplace(emoji, std::weak_ptr()).first; if (const auto result = i->second.lock()) { return result; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h index 9295e3b51..b098b0775 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_pack.h @@ -40,7 +40,7 @@ public: void remove(not_null item); [[nodiscard]] DocumentData *stickerForEmoji(const IsolatedEmoji &emoji); - [[nodiscard]] std::shared_ptr image(const IsolatedEmoji &emoji); + [[nodiscard]] std::shared_ptr image(EmojiPtr emoji); private: class ImageLoader; @@ -62,7 +62,7 @@ private: base::flat_map< IsolatedEmoji, base::flat_set>> _items; - base::flat_map> _images; + base::flat_map> _images; mtpRequestId _requestId = 0; crl::object_on_queue _imageLoader; diff --git a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp index 449fbdbd8..64cdd46ae 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp @@ -20,49 +20,70 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { -std::shared_ptr ResolveImage( - not_null session, - const Ui::Text::IsolatedEmoji &emoji) { - return session->emojiStickersPack().image(emoji); +auto ResolveImages( + not_null session, + const Ui::Text::IsolatedEmoji &emoji) +-> std::array, Ui::Text::kIsolatedEmojiLimit> { + const auto single = [&](EmojiPtr emoji) { + return emoji ? session->emojiStickersPack().image(emoji) : nullptr; + }; + return { { + single(emoji.items[0]), + single(emoji.items[1]), + single(emoji.items[2]) } }; +} + +auto NonEmpty(const std::array, Ui::Text::kIsolatedEmojiLimit> &images) { + using namespace rpl::mappers; + + return images | ranges::view::filter(_1 != nullptr); } } // namespace LargeEmoji::LargeEmoji( not_null parent, - Ui::Text::IsolatedEmoji emoji) + const Ui::Text::IsolatedEmoji &emoji) : _parent(parent) -, _emoji(emoji) -, _image(ResolveImage(&parent->data()->history()->session(), emoji)) { +, _images(ResolveImages(&parent->data()->history()->session(), emoji)) { } QSize LargeEmoji::size() { - const auto size = _image->size() / cIntRetinaFactor(); + using namespace rpl::mappers; + + const auto count = ranges::distance(NonEmpty(_images)); + Assert(count > 0); + + const auto single = _images[0]->size() / cIntRetinaFactor(); + const auto skip = st::largeEmojiSkip - 2 * st::largeEmojiOutline; + const auto inner = count * single.width() + (count - 1) * skip; const auto &padding = st::largeEmojiPadding; _size = QSize( - padding.left() + size.width() + padding.right(), - padding.top() + size.height() + padding.bottom()); + padding.left() + inner + padding.right(), + padding.top() + single.height() + padding.bottom()); return _size; } void LargeEmoji::draw(Painter &p, const QRect &r, bool selected) { - _image->load(Data::FileOrigin()); - if (!_image->loaded()) { - return; - } + auto &&images = NonEmpty(_images); const auto &padding = st::largeEmojiPadding; + auto x = r.x() + (r.width() - _size.width()) / 2 + padding.left(); + const auto y = r.y() + (r.height() - _size.height()) / 2 + padding.top(); const auto o = Data::FileOrigin(); - const auto w = _size.width() - padding.left() - padding.right(); - const auto h = _size.height() - padding.top() - padding.bottom(); - const auto &c = st::msgStickerOverlay; - const auto pixmap = selected - ? _image->pixColored(o, c, w, h) - : _image->pix(o, w, h); - p.drawPixmap( - QPoint( - r.x() + (r.width() - _size.width()) / 2, - r.y() + (r.height() - _size.height()) / 2), - pixmap); + const auto skip = st::largeEmojiSkip - 2 * st::largeEmojiOutline; + for (const auto &image : images) { + image->load(Data::FileOrigin()); + const auto w = image->width() / cIntRetinaFactor(); + if (image->loaded()) { + const auto h = image->height() / cIntRetinaFactor(); + const auto &c = st::msgStickerOverlay; + const auto pixmap = selected + ? image->pixColored(o, c, w, h) + : image->pix(o, w, h); + p.drawPixmap(x, y, pixmap); + } + x += w + skip; + } } } // namespace HistoryView diff --git a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h index 367e282c0..508d09350 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h +++ b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.h @@ -24,15 +24,16 @@ class LargeEmoji final : public UnwrappedMedia::Content { public: LargeEmoji( not_null parent, - Ui::Text::IsolatedEmoji emoji); + const Ui::Text::IsolatedEmoji &emoji); QSize size() override; void draw(Painter &p, const QRect &r, bool selected) override; private: const not_null _parent; - const Ui::Text::IsolatedEmoji _emoji; - std::shared_ptr _image; + const std::array< + std::shared_ptr, + Ui::Text::kIsolatedEmojiLimit> _images; QSize _size; };