Resolve custom emoji in OnlyCustomEmoji media.

This commit is contained in:
John Preston 2022-08-04 14:31:15 +03:00
parent f8e22210e7
commit 543bfab24a
6 changed files with 93 additions and 49 deletions

View File

@ -124,19 +124,7 @@ EmojiPack::~EmojiPack() = default;
bool EmojiPack::add(not_null<HistoryItem*> item) {
if (const auto custom = item->onlyCustomEmoji()) {
auto &ids = _onlyCustomItems[item];
Assert(ids.empty());
auto &manager = item->history()->owner().customEmojiManager();
for (const auto &line : custom.lines) {
for (const auto &element : line) {
const auto &data = element.entityData;
const auto id = Data::ParseCustomEmojiData(data).id;
if (!manager.resolved(id, [] {})) {
ids.emplace(id);
_onlyCustomWaiting[id].emplace(item);
}
}
}
_onlyCustomItems.emplace(item);
return true;
} else if (const auto emoji = item->isolatedEmoji()) {
_items[emoji].emplace(item);
@ -149,16 +137,7 @@ void EmojiPack::remove(not_null<const HistoryItem*> item) {
Expects(item->isIsolatedEmoji() || item->isOnlyCustomEmoji());
if (item->isOnlyCustomEmoji()) {
if (const auto list = _onlyCustomItems.take(item)) {
for (const auto id : *list) {
const auto i = _onlyCustomWaiting.find(id);
Assert(i != end(_onlyCustomWaiting));
i->second.remove(item);
if (i->second.empty()) {
_onlyCustomWaiting.erase(i);
}
}
}
_onlyCustomItems.remove(item);
} else if (const auto emoji = item->isolatedEmoji()) {
const auto i = _items.find(emoji);
Assert(i != end(_items));

View File

@ -107,12 +107,7 @@ private:
base::flat_map<EmojiPtr, std::weak_ptr<LargeEmojiImage>> _images;
mtpRequestId _requestId = 0;
base::flat_map<
not_null<HistoryItem*>,
base::flat_set<DocumentId>> _onlyCustomItems;
base::flat_map<
DocumentId,
base::flat_set<not_null<HistoryItem*>>> _onlyCustomWaiting;
base::flat_set<not_null<HistoryItem*>> _onlyCustomItems;
base::flat_map<
EmojiPtr,

View File

@ -446,22 +446,37 @@ std::unique_ptr<Ui::Text::CustomEmoji> CustomEmojiManager::create(
});
}
bool CustomEmojiManager::resolved(QStringView data, Fn<void()> callback) {
return resolved(ParseCustomEmojiData(data).id, std::move(callback));
void CustomEmojiManager::resolve(
QStringView data,
not_null<Listener*> listener) {
resolve(ParseCustomEmojiData(data).id, listener);
}
bool CustomEmojiManager::resolved(
void CustomEmojiManager::resolve(
DocumentId documentId,
Fn<void()> callback) {
not_null<Listener*> listener) {
if (_owner->document(documentId)->sticker()) {
return true;
return;
}
_resolvers[documentId].push_back(std::move(callback));
_resolvers[documentId].emplace(listener);
_listeners[listener].emplace(documentId);
_pendingForRequest.emplace(documentId);
if (!_requestId && _pendingForRequest.size() == 1) {
crl::on_main(this, [=] { request(); });
}
return false;
}
void CustomEmojiManager::unregisterListener(not_null<Listener*> listener) {
if (const auto list = _listeners.take(listener)) {
for (const auto id : *list) {
const auto i = _resolvers.find(id);
if (i != end(_resolvers)
&& i->second.remove(listener)
&& i->second.empty()) {
_resolvers.erase(i);
}
}
}
}
std::unique_ptr<Ui::CustomEmoji::Loader> CustomEmojiManager::createLoader(
@ -523,9 +538,15 @@ void CustomEmojiManager::request() {
}
}
}
if (const auto callbacks = _resolvers.take(id)) {
for (const auto &callback : *callbacks) {
callback();
if (const auto listeners = _resolvers.take(id)) {
for (const auto &listener : *listeners) {
const auto i = _listeners.find(listener);
if (i != end(_listeners) && i->second.remove(id)) {
if (i->second.empty()) {
_listeners.erase(i);
}
listener->customEmojiResolveDone(document);
}
}
}
requestSetFor(document);

View File

@ -54,8 +54,14 @@ public:
Fn<void()> update,
SizeTag tag = SizeTag::Normal);
bool resolved(QStringView data, Fn<void()> callback);
bool resolved(DocumentId documentId, Fn<void()> callback);
class Listener {
public:
virtual void customEmojiResolveDone(
not_null<DocumentData*> document) = 0;
};
void resolve(QStringView data, not_null<Listener*> listener);
void resolve(DocumentId documentId, not_null<Listener*> listener);
void unregisterListener(not_null<Listener*> listener);
[[nodiscard]] std::unique_ptr<Ui::CustomEmoji::Loader> createLoader(
not_null<DocumentData*> document,
@ -109,7 +115,12 @@ private:
DocumentId,
std::vector<base::weak_ptr<CustomEmojiLoader>>>,
kSizeCount> _loaders;
base::flat_map<DocumentId, std::vector<Fn<void()>>> _resolvers;
base::flat_map<
DocumentId,
base::flat_set<not_null<Listener*>>> _resolvers;
base::flat_map<
not_null<Listener*>,
base::flat_set<DocumentId>> _listeners;
base::flat_set<DocumentId> _pendingForRequest;
mtpRequestId _requestId = 0;

View File

@ -64,7 +64,6 @@ CustomEmoji::CustomEmoji(
: _parent(parent) {
Expects(!emoji.lines.empty());
auto resolving = false;
const auto owner = &parent->data()->history()->owner();
const auto manager = &owner->customEmojiManager();
const auto max = ranges::max_element(
@ -79,6 +78,9 @@ CustomEmoji::CustomEmoji(
_singleSize = !useCustomEmoji
? int(base::SafeRound(i->second.scale * st::maxAnimatedEmojiSize))
: Data::FrameSizeFromTag(tag);
if (!useCustomEmoji) {
_cachingTag = i->second.tag;
}
for (const auto &line : emoji.lines) {
_lines.emplace_back();
for (const auto &element : line) {
@ -98,17 +100,35 @@ CustomEmoji::CustomEmoji(
parent,
document,
skipPremiumEffect);
sticker->setCustomEmojiPart(_singleSize, i->second.tag);
sticker->setCustomEmojiPart(_singleSize, _cachingTag);
_lines.back().push_back(std::move(sticker));
} else {
_lines.back().push_back(element.entityData);
resolving = true;
_lines.back().push_back(id);
manager->resolve(id, listener());
_resolving = true;
}
}
}
}
if (resolving) {
}
void CustomEmoji::customEmojiResolveDone(not_null<DocumentData*> document) {
_resolving = false;
const auto id = document->id;
for (auto &line : _lines) {
for (auto &entry : line) {
if (entry == id) {
const auto skipPremiumEffect = false;
auto sticker = std::make_unique<Sticker>(
_parent,
document,
skipPremiumEffect);
sticker->setCustomEmojiPart(_singleSize, _cachingTag);
entry = std::move(sticker);
} else if (v::is<DocumentId>(entry)) {
_resolving = true;
}
}
}
}
@ -117,6 +137,10 @@ CustomEmoji::~CustomEmoji() {
unloadHeavyPart();
_parent->checkHeavyPart();
}
if (_resolving) {
const auto owner = &_parent->data()->history()->owner();
owner->customEmojiManager().unregisterListener(listener());
}
}
QSize CustomEmoji::countOptimalSize() {

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "history/view/media/history_view_media_unwrapped.h"
#include "data/stickers/data_custom_emoji.h"
namespace Ui::Text {
struct OnlyCustomEmoji;
@ -17,16 +18,22 @@ namespace Stickers {
struct LargeEmojiImage;
} // namespace Stickers
namespace ChatHelpers {
enum class StickerLottieSize : uint8;
} // namespace ChatHelpers
namespace HistoryView {
class Sticker;
using LargeCustomEmoji = std::variant<
QString,
DocumentId,
std::unique_ptr<Sticker>,
std::unique_ptr<Ui::Text::CustomEmoji>>;
class CustomEmoji final : public UnwrappedMedia::Content {
class CustomEmoji final
: public UnwrappedMedia::Content
, private Data::CustomEmojiManager::Listener {
public:
CustomEmoji(
not_null<Element*> parent,
@ -51,6 +58,9 @@ public:
void unloadHeavyPart() override;
private:
[[nodiscard]] not_null<Data::CustomEmojiManager::Listener*> listener() {
return this;
}
void paintElement(
Painter &p,
int x,
@ -73,11 +83,15 @@ private:
const PaintContext &context,
bool paused);
void customEmojiResolveDone(not_null<DocumentData*> document) override;
const not_null<Element*> _parent;
std::vector<std::vector<LargeCustomEmoji>> _lines;
QImage _selectedFrame;
int _singleSize = 0;
ChatHelpers::StickerLottieSize _cachingTag = {};
bool _hasHeavyPart = false;
bool _resolving = false;
};