Change the way scrolled rows are tracked

The goal of this commit is to simplify the logic in TextMetrics::draw.
Now, rows are repainted depending on their changed() status.

Instead of checking whether rows have been scrolled horizontally at
draw time, the code marks the row as changed when testing for
horizontal scrolling.

To this end a new method TestMetrics::setRowChanged is added, that
searches a row in the text metrics cache and marks it changed if
found.

The old code that remembered the previously scrolled row can now be
removed.
This commit is contained in:
Jean-Marc Lasgouttes 2019-02-21 17:52:36 +01:00
parent e69f702275
commit 7f0525e9e0
4 changed files with 29 additions and 36 deletions

View File

@ -316,9 +316,6 @@ struct BufferView::Private
/// a slice pointing to the start of the row where the cursor
/// is (at last draw time)
CursorSlice current_row_slice_;
/// a slice pointing to the start of the row where cursor was
/// at previous draw event
CursorSlice last_row_slice_;
// The vertical size of the blinking caret. Only used for math
// Using it for text could be bad when undo restores the cursor
@ -3066,30 +3063,24 @@ int BufferView::horizScrollOffset(Text const * text,
}
bool BufferView::hadHorizScrollOffset(Text const * text,
pit_type pit, pos_type pos) const
{
return !d->last_row_slice_.empty()
&& &text->inset() == d->last_row_slice_.inset().asInsetText()
&& pit == d->last_row_slice_.pit()
&& pos == d->last_row_slice_.pos();
}
void BufferView::setCurrentRowSlice(CursorSlice const & rowSlice)
{
// nothing to do if the cursor was already on this row
if (d->current_row_slice_ == rowSlice) {
d->last_row_slice_ = CursorSlice();
if (d->current_row_slice_ == rowSlice)
return;
}
// if the (previous) current row was scrolled, we have to
// remember it in order to repaint it next time.
if (d->horiz_scroll_offset_ != 0)
d->last_row_slice_ = d->current_row_slice_;
else
d->last_row_slice_ = CursorSlice();
if (d->horiz_scroll_offset_ != 0) {
// search the old row in cache and mark it changed
for (auto & tm_pair : d->text_metrics_) {
if (&tm_pair.first->inset() == rowSlice.inset().asInsetText()) {
tm_pair.second.setRowChanged(rowSlice.pit(), rowSlice.pos());
// We found it, no need to continue.
break;
}
}
}
// Since we changed row, the scroll offset is not valid anymore
d->horiz_scroll_offset_ = 0;
@ -3146,8 +3137,7 @@ void BufferView::checkCursorScrollOffset()
<< d->horiz_scroll_offset_ << " to " << offset);
if (d->update_strategy_ == NoScreenUpdate
&& (offset != d->horiz_scroll_offset_
|| !d->last_row_slice_.empty())) {
&& offset != d->horiz_scroll_offset_) {
// FIXME: if one uses SingleParUpdate, then home/end
// will not work on long rows. Why?
d->update_strategy_ = FullScreenUpdate;

View File

@ -146,11 +146,6 @@ public:
int horizScrollOffset(Text const * text,
pit_type pit, pos_type pos) const;
// Returns true if the row of text starting at (pit, pos) was scrolled
// at the last draw event.
bool hadHorizScrollOffset(Text const * text,
pit_type pit, pos_type pos) const;
/// reset the scrollbar to reflect current view position.
void updateScrollbar();
/// return the Scrollbar Parameters.

View File

@ -159,6 +159,16 @@ bool TextMetrics::isFirstRow(Row const & row) const
}
void TextMetrics::setRowChanged(pit_type pit, pos_type pos)
{
for (auto & pm_pair : par_metrics_)
if (pm_pair.first == pit)
for (Row & row : pm_pair.second.rows())
if (row.pos() == pos)
row.changed(true);
}
ParagraphMetrics & TextMetrics::parMetrics(pit_type pit, bool redo)
{
ParMetricsCache::iterator pmc_it = par_metrics_.find(pit);
@ -1872,12 +1882,8 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
row.change(row.end_margin_sel, sel_end.pit() > pit);
}
// has row changed since last paint?
bool row_has_changed = row.changed()
|| bv_->hadHorizScrollOffset(text_, pit, row.pos());
// Take this opportunity to spellcheck the row contents.
if (row_has_changed && pi.do_spellcheck && lyxrc.spellcheck_continuously) {
if (row.changed() && pi.do_spellcheck && lyxrc.spellcheck_continuously) {
text_->getPar(pit).spellCheck();
}
@ -1885,7 +1891,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
// Don't paint the row if a full repaint has not been requested
// and if it has not changed.
if (!pi.full_repaint && !row_has_changed) {
if (!pi.full_repaint && !row.changed()) {
// Paint only the insets if the text itself is
// unchanged.
rp.paintOnlyInsets();
@ -1896,7 +1902,7 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
// Clear background of this row if paragraph background was not
// already cleared because of a full repaint.
if (!pi.full_repaint && row_has_changed) {
if (!pi.full_repaint && row.changed()) {
LYXERR(Debug::PAINTING, "Clear rect@("
<< max(row_x, 0) << ", " << y - row.ascent() << ")="
<< width() << " x " << row.height());
@ -1915,13 +1921,13 @@ void TextMetrics::drawParagraph(PainterInfo & pi, pit_type const pit, int const
// Instrumentation for testing row cache (see also
// 12 lines lower):
if (lyxerr.debugging(Debug::PAINTING)
&& (row.selection() || pi.full_repaint || row_has_changed)) {
&& (row.selection() || pi.full_repaint || row.changed())) {
string const foreword = text_->isMainText() ? "main text redraw "
: "inset text redraw: ";
LYXERR0(foreword << "pit=" << pit << " row=" << i
<< (row.selection() ? " row_selection": "")
<< (pi.full_repaint ? " full_repaint" : "")
<< (row_has_changed ? " row_has_changed" : ""));
<< (row.changed() ? " row.changed" : ""));
}
// Backup full_repaint status and force full repaint

View File

@ -49,6 +49,8 @@ public:
bool isLastRow(Row const & row) const;
/// is this row the first in the text?
bool isFirstRow(Row const & row) const;
///
void setRowChanged(pit_type pit, pos_type pos);
///
Dimension const & dim() const { return dim_; }