From 7f0525e9e09459e5bccc8442d889a1aafffa071f Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Thu, 21 Feb 2019 17:52:36 +0100 Subject: [PATCH] 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. --- src/BufferView.cpp | 34 ++++++++++++---------------------- src/BufferView.h | 5 ----- src/TextMetrics.cpp | 24 +++++++++++++++--------- src/TextMetrics.h | 2 ++ 4 files changed, 29 insertions(+), 36 deletions(-) diff --git a/src/BufferView.cpp b/src/BufferView.cpp index a46420e339..50df1aade2 100644 --- a/src/BufferView.cpp +++ b/src/BufferView.cpp @@ -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; diff --git a/src/BufferView.h b/src/BufferView.h index 2478e60934..5bad57ca0e 100644 --- a/src/BufferView.h +++ b/src/BufferView.h @@ -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. diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index 28d0d87b0e..88ffa6f874 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -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 diff --git a/src/TextMetrics.h b/src/TextMetrics.h index ba1371fd87..26156fa100 100644 --- a/src/TextMetrics.h +++ b/src/TextMetrics.h @@ -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_; }