From 1587f9f1b901dbbf74cb7053d3a94d733fe59693 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Wed, 6 Mar 2024 17:32:20 +0300 Subject: [PATCH] Added storage of proper text size with emoji to input field. --- ui/widgets/fields/input_field.cpp | 34 ++++++++++++++++++++----------- ui/widgets/fields/input_field.h | 10 ++++++++- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/ui/widgets/fields/input_field.cpp b/ui/widgets/fields/input_field.cpp index e2527f9..5a273c1 100644 --- a/ui/widgets/fields/input_field.cpp +++ b/ui/widgets/fields/input_field.cpp @@ -1927,7 +1927,7 @@ bool InputField::hasText() const { return (from.next() != till); } -QString InputField::getTextPart( +InputField::TextPart InputField::getTextPart( int start, int end, TagList &outTagsList, @@ -1938,7 +1938,7 @@ QString InputField::getTextPart( if (end >= 0 && end <= start) { outTagsChanged = !outTagsList.isEmpty(); outTagsList.clear(); - return QString(); + return { QString(), 0 }; } if (start < 0) { @@ -1967,6 +1967,7 @@ QString InputField::getTextPart( if (!full && end < 0) { end = possibleLength; } + auto textSizeWithoutSurrogatePairsCount = document->characterCount() - 1; for (auto block = from; block != till;) { for (auto item = block.begin(); !item.atEnd(); ++item) { @@ -1993,14 +1994,19 @@ QString InputField::getTextPart( } } - const auto emojiText = [&] { + struct EmojiEntry final { + QString text; + uint8 surrogatePairs = 0; + }; + + const auto emojiEntry = [&]() -> EmojiEntry { if (format.isImageFormat()) { const auto imageName = format.toImageFormat().name(); if (const auto emoji = Emoji::FromUrl(imageName)) { - return emoji->text(); + return { emoji->text(), emoji->surrogatePairs() }; } } - return format.property(kCustomEmojiText).toString(); + return { format.property(kCustomEmojiText).toString(), 0 }; }(); auto text = [&] { const auto result = fragment.text(); @@ -2030,9 +2036,12 @@ QString InputField::getTextPart( if (ch > begin) { result.append(begin, ch - begin); } - adjustedLength += (emojiText.size() - 1); - if (!emojiText.isEmpty()) { - result.append(emojiText); + const auto size = emojiEntry.text.size() - 1; + adjustedLength += size; + if (!emojiEntry.text.isEmpty()) { + result.append(emojiEntry.text); + textSizeWithoutSurrogatePairsCount += size + - emojiEntry.surrogatePairs; } begin = ch + 1; } break; @@ -2063,7 +2072,7 @@ QString InputField::getTextPart( markdownTagAccumulator.finish(); outTagsChanged = tagAccumulator.changed(); - return result; + return { result, textSizeWithoutSurrogatePairsCount }; } bool InputField::isUndoAvailable() const { @@ -2457,7 +2466,7 @@ void InputField::handleContentsChanged() { setErrorShown(false); auto tagsChanged = false; - const auto currentText = getTextPart( + const auto [currentText, currentTextSize] = getTextPart( 0, -1, _lastTextWithTags.tags, @@ -2466,6 +2475,7 @@ void InputField::handleContentsChanged() { //highlightMarkdown(); + _lastTextSizeWithoutSurrogatePairsCount = currentTextSize; if (tagsChanged || (_lastTextWithTags.text != currentText)) { _lastTextWithTags.text = currentText; const auto weak = MakeWeak(this); @@ -2640,7 +2650,7 @@ void InputField::setTextWithTags( TextWithTags InputField::getTextWithTagsPart(int start, int end) const { auto changed = false; auto result = TextWithTags(); - result.text = getTextPart(start, end, result.tags, changed); + result.text = getTextPart(start, end, result.tags, changed).text; return result; } @@ -3988,7 +3998,7 @@ void PrepareFormattingOptimization(not_null document) { int FieldCharacterCount(not_null field) { // This method counts emoji properly. - return field->document()->characterCount() - 1; + return field->lastTextSizeWithoutSurrogatePairsCount(); } } // namespace Ui diff --git a/ui/widgets/fields/input_field.h b/ui/widgets/fields/input_field.h index 3b3d978..167f8a2 100644 --- a/ui/widgets/fields/input_field.h +++ b/ui/widgets/fields/input_field.h @@ -241,6 +241,9 @@ public: const QString &getLastText() const { return _lastTextWithTags.text; } + [[nodiscard]] int lastTextSizeWithoutSurrogatePairsCount() const { + return _lastTextSizeWithoutSurrogatePairsCount; + } void setPlaceholder( rpl::producer placeholder, int afterSymbols = 0); @@ -380,7 +383,11 @@ private: // "start" and "end" are in coordinates of text where emoji are replaced // by ObjectReplacementCharacter. If "end" = -1 means get text till the end. - QString getTextPart( + struct TextPart final { + QString text; + int textSizeWithoutSurrogatePairsCount = 0; + }; + TextPart getTextPart( int start, int end, TagList &outTagsList, @@ -484,6 +491,7 @@ private: TextWithTags _lastTextWithTags; std::vector _lastMarkdownTags; QString _lastPreEditText; + int _lastTextSizeWithoutSurrogatePairsCount = 0; std::optional _inputMethodCommit; QMargins _additionalMargins;