From 8915f5d40d1040f8408a59dfb552aaee73705a4e Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 17 Oct 2023 12:01:50 +0400 Subject: [PATCH] Fix modifications tracking with skip block. --- ui/text/text.cpp | 57 ++++++++++++++++++++++++++++++++++++++--- ui/text/text.h | 2 ++ ui/text/text_parser.cpp | 35 +++++-------------------- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/ui/text/text.cpp b/ui/text/text.cpp index a4ba32e..af66be4 100644 --- a/ui/text/text.cpp +++ b/ui/text/text.cpp @@ -673,9 +673,12 @@ bool String::updateSkipBlock(int width, int height) { if (block->f_width().toInt() == width && block->height() == height) { return false; } - _text.resize(block->position()); + const auto size = block->position(); + _text.resize(size); _blocks.pop_back(); + removeModificationsAfter(size); } else if (_endsWithQuote) { + insertModifications(_text.size(), 1); _text.push_back(QChar::LineFeed); _blocks.push_back(Block::Newline( _st->font, @@ -687,6 +690,7 @@ bool String::updateSkipBlock(int width, int height) { 0)); _skipBlockAddedNewline = true; } + insertModifications(_text.size(), 1); _text.push_back('_'); _blocks.push_back(Block::Skip( _st->font, @@ -704,18 +708,65 @@ bool String::removeSkipBlock() { if (_blocks.empty() || _blocks.back()->type() != TextBlockType::Skip) { return false; } else if (_skipBlockAddedNewline) { - _text.resize(_blocks.back()->position() - 1); + const auto size = _blocks.back()->position() - 1; + _text.resize(size); _blocks.pop_back(); _blocks.pop_back(); _skipBlockAddedNewline = false; + removeModificationsAfter(size); } else { - _text.resize(_blocks.back()->position()); + const auto size = _blocks.back()->position(); + _text.resize(size); _blocks.pop_back(); + removeModificationsAfter(size); } recountNaturalSize(false); return true; } +void String::insertModifications(int position, int delta) { + auto &modifications = ensureExtended()->modifications; + auto i = end(modifications); + while (i != begin(modifications) && (--i)->position >= position) { + if (i->position < position) { + break; + } else if (delta > 0) { + ++i->position; + } else if (i->position == position) { + break; + } + } + if (i != end(modifications) && i->position == position) { + ++i->skipped; + } else { + modifications.insert(i, { + .position = position, + .skipped = uint16(delta < 0 ? (-delta) : 0), + .added = (delta > 0), + }); + } +} + +void String::removeModificationsAfter(int size) { + if (!_extended) { + return; + } + auto &modifications = _extended->modifications; + for (auto i = end(modifications); i != begin(modifications);) { + --i; + if (i->position > size) { + i = modifications.erase(i); + } else if (i->position == size) { + i->added = false; + if (!i->skipped) { + i = modifications.erase(i); + } + } else { + break; + } + } +} + int String::countWidth(int width, bool breakEverywhere) const { if (QFixed(width) >= _maxWidth) { return _maxWidth; diff --git a/ui/text/text.h b/ui/text/text.h index 4ee53ec..bb412a1 100644 --- a/ui/text/text.h +++ b/ui/text/text.h @@ -407,6 +407,8 @@ private: bool breakEverywhere, Callback callback) const; + void insertModifications(int position, int delta); + void removeModificationsAfter(int size); void recountNaturalSize( bool initial, Qt::LayoutDirection optionsDir = Qt::LayoutDirectionAuto); diff --git a/ui/text/text_parser.cpp b/ui/text/text_parser.cpp index 393c59e..27de57a 100644 --- a/ui/text/text_parser.cpp +++ b/ui/text/text_parser.cpp @@ -183,7 +183,7 @@ void Parser::createBlock(int32 skipBack) { if (_newlineAwaited) { _newlineAwaited = false; if (!newline) { - updateModifications(_blockStart, 1); + _t->insertModifications(_blockStart, 1); _t->_text.insert(_blockStart, QChar::LineFeed); createBlock(skipBack - length); } @@ -226,7 +226,7 @@ void Parser::createBlock(int32 skipBack) { void Parser::createNewlineBlock(bool fromOriginalText) { if (!fromOriginalText) { - updateModifications(_t->_text.size(), 1); + _t->insertModifications(_t->_text.size(), 1); } _t->_text.push_back(QChar::LineFeed); _allowDiacritic = false; @@ -523,7 +523,9 @@ void Parser::parseCurrentChar() { } if (skip) { - updateModifications(_t->_text.size(), -1); + if (_ptr < _end) { + _t->insertModifications(_t->_text.size(), -1); + } _ch = 0; _allowDiacritic = false; } else { @@ -572,7 +574,7 @@ void Parser::parseEmojiFromCurrent() { Assert(!_t->_text.isEmpty()); const auto last = _t->_text[_t->_text.size() - 1]; if (last.unicode() != Emoji::kPostfix) { - updateModifications(_t->_text.size(), 1); + _t->insertModifications(_t->_text.size(), 1); _t->_text.push_back(QChar(Emoji::kPostfix)); ++len; } @@ -602,29 +604,6 @@ bool Parser::isLinkEntity(const EntityInText &entity) const { return ranges::find(urls, type) != std::end(urls); } -void Parser::updateModifications(int index, int delta) { - auto &modifications = _t->ensureExtended()->modifications; - auto i = end(modifications); - while (i != begin(modifications) && (--i)->position >= index) { - if (i->position < index) { - break; - } else if (delta > 0) { - ++i->position; - } else if (i->position == index) { - break; - } - } - if (i != end(modifications) && i->position == index) { - ++i->skipped; - } else { - modifications.insert(i, { - .position = index, - .skipped = uint16(delta < 0 ? 1 : 0), - .added = (delta > 0), - }); - } -} - void Parser::parse(const TextParseOptions &options) { skipBadEntities(); trimSourceRange(); @@ -636,7 +615,7 @@ void Parser::parse(const TextParseOptions &options) { _t->_text.reserve(_end - _ptr); if (_ptr > _start) { - updateModifications(0, -(_ptr - _start)); + _t->insertModifications(0, -(_ptr - _start)); } for (; _ptr <= _end; ++_ptr) {