Added storage of proper text size with emoji to input field.

This commit is contained in:
23rd 2024-03-06 17:32:20 +03:00 committed by John Preston
parent 3c8cf5f5db
commit 1587f9f1b9
2 changed files with 31 additions and 13 deletions

View file

@ -1927,7 +1927,7 @@ bool InputField::hasText() const {
return (from.next() != till); return (from.next() != till);
} }
QString InputField::getTextPart( InputField::TextPart InputField::getTextPart(
int start, int start,
int end, int end,
TagList &outTagsList, TagList &outTagsList,
@ -1938,7 +1938,7 @@ QString InputField::getTextPart(
if (end >= 0 && end <= start) { if (end >= 0 && end <= start) {
outTagsChanged = !outTagsList.isEmpty(); outTagsChanged = !outTagsList.isEmpty();
outTagsList.clear(); outTagsList.clear();
return QString(); return { QString(), 0 };
} }
if (start < 0) { if (start < 0) {
@ -1967,6 +1967,7 @@ QString InputField::getTextPart(
if (!full && end < 0) { if (!full && end < 0) {
end = possibleLength; end = possibleLength;
} }
auto textSizeWithoutSurrogatePairsCount = document->characterCount() - 1;
for (auto block = from; block != till;) { for (auto block = from; block != till;) {
for (auto item = block.begin(); !item.atEnd(); ++item) { 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()) { if (format.isImageFormat()) {
const auto imageName = format.toImageFormat().name(); const auto imageName = format.toImageFormat().name();
if (const auto emoji = Emoji::FromUrl(imageName)) { 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 = [&] { auto text = [&] {
const auto result = fragment.text(); const auto result = fragment.text();
@ -2030,9 +2036,12 @@ QString InputField::getTextPart(
if (ch > begin) { if (ch > begin) {
result.append(begin, ch - begin); result.append(begin, ch - begin);
} }
adjustedLength += (emojiText.size() - 1); const auto size = emojiEntry.text.size() - 1;
if (!emojiText.isEmpty()) { adjustedLength += size;
result.append(emojiText); if (!emojiEntry.text.isEmpty()) {
result.append(emojiEntry.text);
textSizeWithoutSurrogatePairsCount += size
- emojiEntry.surrogatePairs;
} }
begin = ch + 1; begin = ch + 1;
} break; } break;
@ -2063,7 +2072,7 @@ QString InputField::getTextPart(
markdownTagAccumulator.finish(); markdownTagAccumulator.finish();
outTagsChanged = tagAccumulator.changed(); outTagsChanged = tagAccumulator.changed();
return result; return { result, textSizeWithoutSurrogatePairsCount };
} }
bool InputField::isUndoAvailable() const { bool InputField::isUndoAvailable() const {
@ -2457,7 +2466,7 @@ void InputField::handleContentsChanged() {
setErrorShown(false); setErrorShown(false);
auto tagsChanged = false; auto tagsChanged = false;
const auto currentText = getTextPart( const auto [currentText, currentTextSize] = getTextPart(
0, 0,
-1, -1,
_lastTextWithTags.tags, _lastTextWithTags.tags,
@ -2466,6 +2475,7 @@ void InputField::handleContentsChanged() {
//highlightMarkdown(); //highlightMarkdown();
_lastTextSizeWithoutSurrogatePairsCount = currentTextSize;
if (tagsChanged || (_lastTextWithTags.text != currentText)) { if (tagsChanged || (_lastTextWithTags.text != currentText)) {
_lastTextWithTags.text = currentText; _lastTextWithTags.text = currentText;
const auto weak = MakeWeak(this); const auto weak = MakeWeak(this);
@ -2640,7 +2650,7 @@ void InputField::setTextWithTags(
TextWithTags InputField::getTextWithTagsPart(int start, int end) const { TextWithTags InputField::getTextWithTagsPart(int start, int end) const {
auto changed = false; auto changed = false;
auto result = TextWithTags(); auto result = TextWithTags();
result.text = getTextPart(start, end, result.tags, changed); result.text = getTextPart(start, end, result.tags, changed).text;
return result; return result;
} }
@ -3988,7 +3998,7 @@ void PrepareFormattingOptimization(not_null<QTextDocument*> document) {
int FieldCharacterCount(not_null<InputField*> field) { int FieldCharacterCount(not_null<InputField*> field) {
// This method counts emoji properly. // This method counts emoji properly.
return field->document()->characterCount() - 1; return field->lastTextSizeWithoutSurrogatePairsCount();
} }
} // namespace Ui } // namespace Ui

View file

@ -241,6 +241,9 @@ public:
const QString &getLastText() const { const QString &getLastText() const {
return _lastTextWithTags.text; return _lastTextWithTags.text;
} }
[[nodiscard]] int lastTextSizeWithoutSurrogatePairsCount() const {
return _lastTextSizeWithoutSurrogatePairsCount;
}
void setPlaceholder( void setPlaceholder(
rpl::producer<QString> placeholder, rpl::producer<QString> placeholder,
int afterSymbols = 0); int afterSymbols = 0);
@ -380,7 +383,11 @@ private:
// "start" and "end" are in coordinates of text where emoji are replaced // "start" and "end" are in coordinates of text where emoji are replaced
// by ObjectReplacementCharacter. If "end" = -1 means get text till the end. // 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 start,
int end, int end,
TagList &outTagsList, TagList &outTagsList,
@ -484,6 +491,7 @@ private:
TextWithTags _lastTextWithTags; TextWithTags _lastTextWithTags;
std::vector<MarkdownTag> _lastMarkdownTags; std::vector<MarkdownTag> _lastMarkdownTags;
QString _lastPreEditText; QString _lastPreEditText;
int _lastTextSizeWithoutSurrogatePairsCount = 0;
std::optional<QString> _inputMethodCommit; std::optional<QString> _inputMethodCommit;
QMargins _additionalMargins; QMargins _additionalMargins;