From f27d756bcd7508250a3f7ff73bf6053308c18cd6 Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 3 Aug 2022 20:07:43 +0300 Subject: [PATCH] Support getting OnlyCustomEmoji from Ui::Text::String. --- ui/text/text.cpp | 71 +++++++++++++++++++++++++++++++++-- ui/text/text.h | 16 ++++++-- ui/text/text_isolated_emoji.h | 15 +++++++- 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/ui/text/text.cpp b/ui/text/text.cpp index 70e870d..ab84086 100644 --- a/ui/text/text.cpp +++ b/ui/text/text.cpp @@ -836,10 +836,28 @@ void Parser::finalize(const TextParseOptions &options) { currentIndex++; } }; + auto isolatedEmojiCount = 0; _t->_hasCustomEmoji = false; + _t->_isIsolatedEmoji = true; + _t->_isOnlyCustomEmoji = true; for (auto &block : _t->_blocks) { if (block->type() == TextBlockTCustomEmoji) { _t->_hasCustomEmoji = true; + } else if (block->type() != TextBlockTNewline + && block->type() != TextBlockTSkip) { + _t->_isOnlyCustomEmoji = false; + } else if (block->lnkIndex()) { + _t->_isOnlyCustomEmoji = _t->_isIsolatedEmoji = false; + } + if (_t->_isIsolatedEmoji) { + if (block->type() == TextBlockTCustomEmoji + || block->type() == TextBlockTEmoji) { + if (++isolatedEmojiCount > kIsolatedEmojiLimit) { + _t->_isIsolatedEmoji = false; + } + } else if (block->type() != TextBlockTSkip) { + _t->_isIsolatedEmoji = false; + } } const auto spoilerIndex = block->spoilerIndex(); if (spoilerIndex && (_t->_spoilers.size() < spoilerIndex)) { @@ -906,6 +924,12 @@ void Parser::finalize(const TextParseOptions &options) { } lastHandlerIndex.lnk = realIndex; } + if (!_t->_hasCustomEmoji || !_t->_spoilers.empty()) { + _t->_isOnlyCustomEmoji = false; + } + if (_t->_blocks.empty() || !_t->_spoilers.empty()) { + _t->_isIsolatedEmoji = false; + } _t->_links.squeeze(); _t->_spoilers.squeeze(); _t->_blocks.shrink_to_fit(); @@ -2916,11 +2940,20 @@ private: }; -String::String(int32 minResizeWidth) : _minResizeWidth(minResizeWidth) { +String::String(int32 minResizeWidth) +: _minResizeWidth(minResizeWidth) +, _hasCustomEmoji(false) +, _isOnlyCustomEmoji(false) { } -String::String(const style::TextStyle &st, const QString &text, const TextParseOptions &options, int32 minResizeWidth) -: _minResizeWidth(minResizeWidth) { +String::String( + const style::TextStyle &st, + const QString &text, + const TextParseOptions &options, + int32 minResizeWidth) +: _minResizeWidth(minResizeWidth) +, _hasCustomEmoji(false) +, _isOnlyCustomEmoji(false) { setText(st, text, options); } @@ -3552,6 +3585,31 @@ void String::unloadCustomEmoji() { } } +bool String::isOnlyCustomEmoji() const { + return _isOnlyCustomEmoji; +} + +OnlyCustomEmoji String::toOnlyCustomEmoji() const { + if (!_isOnlyCustomEmoji) { + return {}; + } + auto result = OnlyCustomEmoji(); + auto spaces = 0; + result.lines.emplace_back(); + for (const auto &block : _blocks) { + const auto raw = block.get(); + if (raw->type() == TextBlockTCustomEmoji) { + const auto custom = static_cast(raw); + result.lines.back().push_back({ + .entityData = custom->_custom->entityData(), + }); + } else if (raw->type() == TextBlockTNewline) { + result.lines.emplace_back(); + } + } + return result; +} + QString String::toString(TextSelection selection) const { return toText(selection, false, false).rich.text; } @@ -3715,7 +3773,14 @@ TextForMimeData String::toText( return result; } +bool String::isIsolatedEmoji() const { + return _isIsolatedEmoji; +} + IsolatedEmoji String::toIsolatedEmoji() const { + if (!_isIsolatedEmoji) { + return {}; + } auto result = IsolatedEmoji(); const auto skip = (_blocks.empty() || _blocks.back()->type() != TextBlockTSkip) ? 0 : 1; diff --git a/ui/text/text.h b/ui/text/text.h index 83c2273..6f810ad 100644 --- a/ui/text/text.h +++ b/ui/text/text.h @@ -63,6 +63,7 @@ static constexpr TextSelection AllTextSelection = { 0, 0xFFFF }; namespace Ui::Text { struct IsolatedEmoji; +struct OnlyCustomEmoji; struct StateRequest { enum class Flag { @@ -160,17 +161,22 @@ public: return _text.size(); } - [[nodiscard]] bool hasCustomEmoji() const; - void unloadCustomEmoji(); - [[nodiscard]] QString toString( TextSelection selection = AllTextSelection) const; [[nodiscard]] TextWithEntities toTextWithEntities( TextSelection selection = AllTextSelection) const; [[nodiscard]] TextForMimeData toTextForMimeData( TextSelection selection = AllTextSelection) const; + + [[nodiscard]] bool hasCustomEmoji() const; + void unloadCustomEmoji(); + + [[nodiscard]] bool isIsolatedEmoji() const; [[nodiscard]] IsolatedEmoji toIsolatedEmoji() const; + [[nodiscard]] bool isOnlyCustomEmoji() const; + [[nodiscard]] OnlyCustomEmoji toOnlyCustomEmoji() const; + [[nodiscard]] const style::TextStyle *style() const { return _st; } @@ -210,7 +216,9 @@ private: QFixed _minResizeWidth; QFixed _maxWidth = 0; int32 _minHeight = 0; - bool _hasCustomEmoji = false; + bool _hasCustomEmoji : 1; + bool _isIsolatedEmoji : 1; + bool _isOnlyCustomEmoji : 1; QString _text; const style::TextStyle *_st = nullptr; diff --git a/ui/text/text_isolated_emoji.h b/ui/text/text_isolated_emoji.h index c3b5ce7..d73ef66 100644 --- a/ui/text/text_isolated_emoji.h +++ b/ui/text/text_isolated_emoji.h @@ -43,6 +43,19 @@ struct IsolatedEmoji { } }; -constexpr auto t = sizeof(IsolatedEmoji); +struct OnlyCustomEmoji { + struct Item { + QString entityData; + int spacesBefore = 0; + }; + std::vector> lines; + + [[nodiscard]] bool empty() const { + return lines.empty(); + } + [[nodiscard]] explicit operator bool() const { + return !empty(); + } +}; } // namespace Ui::Text