Fix modifications tracking with skip block.

This commit is contained in:
John Preston 2023-10-17 12:01:50 +04:00
parent 9eb9fcf043
commit 8915f5d40d
3 changed files with 63 additions and 31 deletions

View file

@ -673,9 +673,12 @@ bool String::updateSkipBlock(int width, int height) {
if (block->f_width().toInt() == width && block->height() == height) { if (block->f_width().toInt() == width && block->height() == height) {
return false; return false;
} }
_text.resize(block->position()); const auto size = block->position();
_text.resize(size);
_blocks.pop_back(); _blocks.pop_back();
removeModificationsAfter(size);
} else if (_endsWithQuote) { } else if (_endsWithQuote) {
insertModifications(_text.size(), 1);
_text.push_back(QChar::LineFeed); _text.push_back(QChar::LineFeed);
_blocks.push_back(Block::Newline( _blocks.push_back(Block::Newline(
_st->font, _st->font,
@ -687,6 +690,7 @@ bool String::updateSkipBlock(int width, int height) {
0)); 0));
_skipBlockAddedNewline = true; _skipBlockAddedNewline = true;
} }
insertModifications(_text.size(), 1);
_text.push_back('_'); _text.push_back('_');
_blocks.push_back(Block::Skip( _blocks.push_back(Block::Skip(
_st->font, _st->font,
@ -704,18 +708,65 @@ bool String::removeSkipBlock() {
if (_blocks.empty() || _blocks.back()->type() != TextBlockType::Skip) { if (_blocks.empty() || _blocks.back()->type() != TextBlockType::Skip) {
return false; return false;
} else if (_skipBlockAddedNewline) { } 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();
_blocks.pop_back(); _blocks.pop_back();
_skipBlockAddedNewline = false; _skipBlockAddedNewline = false;
removeModificationsAfter(size);
} else { } else {
_text.resize(_blocks.back()->position()); const auto size = _blocks.back()->position();
_text.resize(size);
_blocks.pop_back(); _blocks.pop_back();
removeModificationsAfter(size);
} }
recountNaturalSize(false); recountNaturalSize(false);
return true; 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 { int String::countWidth(int width, bool breakEverywhere) const {
if (QFixed(width) >= _maxWidth) { if (QFixed(width) >= _maxWidth) {
return _maxWidth; return _maxWidth;

View file

@ -407,6 +407,8 @@ private:
bool breakEverywhere, bool breakEverywhere,
Callback callback) const; Callback callback) const;
void insertModifications(int position, int delta);
void removeModificationsAfter(int size);
void recountNaturalSize( void recountNaturalSize(
bool initial, bool initial,
Qt::LayoutDirection optionsDir = Qt::LayoutDirectionAuto); Qt::LayoutDirection optionsDir = Qt::LayoutDirectionAuto);

View file

@ -183,7 +183,7 @@ void Parser::createBlock(int32 skipBack) {
if (_newlineAwaited) { if (_newlineAwaited) {
_newlineAwaited = false; _newlineAwaited = false;
if (!newline) { if (!newline) {
updateModifications(_blockStart, 1); _t->insertModifications(_blockStart, 1);
_t->_text.insert(_blockStart, QChar::LineFeed); _t->_text.insert(_blockStart, QChar::LineFeed);
createBlock(skipBack - length); createBlock(skipBack - length);
} }
@ -226,7 +226,7 @@ void Parser::createBlock(int32 skipBack) {
void Parser::createNewlineBlock(bool fromOriginalText) { void Parser::createNewlineBlock(bool fromOriginalText) {
if (!fromOriginalText) { if (!fromOriginalText) {
updateModifications(_t->_text.size(), 1); _t->insertModifications(_t->_text.size(), 1);
} }
_t->_text.push_back(QChar::LineFeed); _t->_text.push_back(QChar::LineFeed);
_allowDiacritic = false; _allowDiacritic = false;
@ -523,7 +523,9 @@ void Parser::parseCurrentChar() {
} }
if (skip) { if (skip) {
updateModifications(_t->_text.size(), -1); if (_ptr < _end) {
_t->insertModifications(_t->_text.size(), -1);
}
_ch = 0; _ch = 0;
_allowDiacritic = false; _allowDiacritic = false;
} else { } else {
@ -572,7 +574,7 @@ void Parser::parseEmojiFromCurrent() {
Assert(!_t->_text.isEmpty()); Assert(!_t->_text.isEmpty());
const auto last = _t->_text[_t->_text.size() - 1]; const auto last = _t->_text[_t->_text.size() - 1];
if (last.unicode() != Emoji::kPostfix) { if (last.unicode() != Emoji::kPostfix) {
updateModifications(_t->_text.size(), 1); _t->insertModifications(_t->_text.size(), 1);
_t->_text.push_back(QChar(Emoji::kPostfix)); _t->_text.push_back(QChar(Emoji::kPostfix));
++len; ++len;
} }
@ -602,29 +604,6 @@ bool Parser::isLinkEntity(const EntityInText &entity) const {
return ranges::find(urls, type) != std::end(urls); 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) { void Parser::parse(const TextParseOptions &options) {
skipBadEntities(); skipBadEntities();
trimSourceRange(); trimSourceRange();
@ -636,7 +615,7 @@ void Parser::parse(const TextParseOptions &options) {
_t->_text.reserve(_end - _ptr); _t->_text.reserve(_end - _ptr);
if (_ptr > _start) { if (_ptr > _start) {
updateModifications(0, -(_ptr - _start)); _t->insertModifications(0, -(_ptr - _start));
} }
for (; _ptr <= _end; ++_ptr) { for (; _ptr <= _end; ++_ptr) {