From e7ef29fa2d516b8593aa3cccb6548de5686e8a9a Mon Sep 17 00:00:00 2001 From: Martin Vermeer Date: Fri, 30 Dec 2005 19:02:52 +0000 Subject: [PATCH] The speed patch: redraw only rows that have changed git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@10692 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/ChangeLog | 9 ++++ src/RowList_fwd.h | 3 ++ src/paragraph.C | 4 +- src/paragraph.h | 7 ++- src/rowpainter.C | 109 ++++++++++++++++++++++++++++++++++++---------- 5 files changed, 106 insertions(+), 26 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 85313927c0..58d78eb6d2 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2005-12-30 Martin Vermeer + + * RowList_fwd.h: + * paragraph.C: + * paragraph.h: + * rowpainter.C: Speed up rendering by only re-painting rows that + have changed. When selection or whole-screen update active, all rows + are repainted, as are all rows within insets. + 2005-12-30 Georg Baum * version.C.in: Use PACKAGE_VERSION instead of VERSION diff --git a/src/RowList_fwd.h b/src/RowList_fwd.h index c1a4de1cf1..55e22ab1e2 100644 --- a/src/RowList_fwd.h +++ b/src/RowList_fwd.h @@ -15,6 +15,7 @@ #include "lyxrow.h" #include +#include /** * Each paragraph is broken up into a number of rows on the screen. @@ -22,5 +23,7 @@ * downwards. */ typedef std::vector RowList; +/// +typedef std::map RowSignature; #endif diff --git a/src/paragraph.C b/src/paragraph.C index 6588be1934..227568b43f 100644 --- a/src/paragraph.C +++ b/src/paragraph.C @@ -81,7 +81,8 @@ Paragraph::Paragraph() Paragraph::Paragraph(Paragraph const & par) : itemdepth(par.itemdepth), insetlist(par.insetlist), dim_(par.dim_), - rows_(par.rows_), layout_(par.layout_), + rows_(par.rows_), rowSignature_(par.rowSignature_), + layout_(par.layout_), text_(par.text_), begin_of_body_(par.begin_of_body_), pimpl_(new Paragraph::Pimpl(*par.pimpl_, this)) { @@ -107,6 +108,7 @@ Paragraph & Paragraph::operator=(Paragraph const & par) rows_ = par.rows_; dim_ = par.dim_; + rowSignature_ = par.rowSignature_; layout_ = par.layout(); text_ = par.text_; begin_of_body_ = par.begin_of_body_; diff --git a/src/paragraph.h b/src/paragraph.h index 13c99ca873..9cb720cfb7 100644 --- a/src/paragraph.h +++ b/src/paragraph.h @@ -391,7 +391,9 @@ public: RowList & rows() { return rows_; } /// The painter and others use this RowList const & rows() const { return rows_; } - + /// + RowSignature & rowSignature() const { return rowSignature_; } + /// LyXText::redoParagraph updates this Dimension & dim() { return dim_; } @@ -408,6 +410,9 @@ private: /// mutable RowList rows_; + /// + mutable RowSignature rowSignature_; + /// LyXLayout_ptr layout_; /** diff --git a/src/rowpainter.C b/src/rowpainter.C index 75a8f1fb1f..91543fa30e 100644 --- a/src/rowpainter.C +++ b/src/rowpainter.C @@ -40,6 +40,8 @@ #include "support/textutils.h" +#include + using lyx::pos_type; using lyx::pit_type; @@ -716,8 +718,35 @@ void RowPainter::paintText() } +lyx::size_type calculateRowSignature(Row const & row, Paragraph const & par) +{ + boost::crc_32_type crc; + for (lyx::pos_type i = row.pos(); i < row.endpos(); ++i) { + const unsigned char b[] = { par.getChar(i) }; + crc.process_bytes(b, 1); + } + return crc.checksum(); +} + + +bool isCursorInInsetInRow(PainterInfo & pi, RowList::const_iterator rit, + Paragraph const & par) +{ + InsetList::const_iterator ii = par.insetlist.begin(); + InsetList::const_iterator iend = par.insetlist.end(); + for ( ; ii != iend; ++ii) { + if (ii->pos >= rit->pos() && ii->pos < rit->endpos() + && ii->inset->isTextInset() + && pi.base.bv->cursor().isInside(ii->inset)) + return true; + } + return false; +} + + void paintPar - (PainterInfo & pi, LyXText const & text, pit_type pit, int x, int y) + (PainterInfo & pi, LyXText const & text, pit_type pit, int x, int y, + bool repaintAll) { // lyxerr << " paintPar: pit: " << pit << " at y: " << y << endl; static NullPainter nop; @@ -731,22 +760,51 @@ void paintPar theCoords.parPos()[&text][pit] = Point(x, y); y -= rb->ascent(); - for (RowList::const_iterator rit = rb; rit != re; ++rit) { + lyx::size_type rowno(0); + for (RowList::const_iterator rit = rb; rit != re; ++rit, ++rowno) { y += rit->ascent(); - bool const inside = (y + rit->descent() >= 0 - && y - rit->ascent() < ww); - RowPainter rp(inside ? pi : nullpi, text, pit, *rit, x, y); + // Row signature; has row changed since last paint? + lyx::size_type const row_sig = calculateRowSignature(*rit, par); + + // The following code figures out if the cursor is inside + // an inset _on this row_. + bool cur_in_inset_in_row = isCursorInInsetInRow(pi, rit, par); + + // If selection is on, the current row signature differs from + // from cache, or cursor is inside an inset _on this row_, + // then paint the row + if (repaintAll || par.rowSignature()[rowno] != row_sig + || cur_in_inset_in_row) { + // Add to row signature cache + par.rowSignature()[rowno] = row_sig; + + bool const inside = (y + rit->descent() >= 0 + && y - rit->ascent() < ww); + RowPainter rp(inside ? pi : nullpi, text, pit, *rit, x, y); + // Clear background of this row + // (if paragraph background was not cleared) + if (!repaintAll) { + pi.pain.fillRectangle(x, y - rit->ascent(), + pi.base.bv->workWidth(), rit->height(), + text.backgroundColor()); + } + + // Instrumentation for testing row cache (see also + // 12 lines lower): + //lyxerr << "#"; + rp.paintAppendix(); + rp.paintDepthBar(); + rp.paintChangeBar(); + if (rit == rb) + rp.paintFirst(); + if (rit + 1 == re) + rp.paintLast(); + rp.paintText(); + } y += rit->descent(); - rp.paintAppendix(); - rp.paintDepthBar(); - rp.paintChangeBar(); - if (rit == rb) - rp.paintFirst(); - if (rit + 1 == re) - rp.paintLast(); - rp.paintText(); } + //lyxerr << "." << endl; } } // namespace anon @@ -756,22 +814,25 @@ void paintText(BufferView const & bv, ViewMetricsInfo const & vi) { Painter & pain = bv.painter(); LyXText * const text = bv.text(); + bool const select = bv.cursor().selection(); - // clear background - pain.fillRectangle(0, vi.y1, bv.workWidth(), vi.y2 - vi.y1, - LColor::background); - - // draw selection PainterInfo pi(const_cast(&bv), pain); - - text->drawSelection(pi, 0, 0); + if (select || !vi.singlepar) { + // Clear background (Delegated to rows if no selection) + pain.fillRectangle(0, vi.y1, bv.workWidth(), vi.y2 - vi.y1, + text->backgroundColor()); + } + if (select) { + text->drawSelection(pi, 0, 0); + } int yy = vi.y1; // draw contents for (pit_type pit = vi.p1; pit <= vi.p2; ++pit) { - yy += text->getPar(pit).ascent(); - paintPar(pi, *bv.text(), pit, 0, yy); - yy += text->getPar(pit).descent(); + Paragraph const & par = text->getPar(pit); + yy += par.ascent(); + paintPar(pi, *bv.text(), pit, 0, yy, select || !vi.singlepar); + yy += par.descent(); } // Cache one paragraph above and one below @@ -809,7 +870,7 @@ void paintTextInset(LyXText const & text, PainterInfo & pi, int x, int y) y -= text.getPar(0).ascent(); for (int pit = 0; pit < int(text.paragraphs().size()); ++pit) { y += text.getPar(pit).ascent(); - paintPar(pi, text, pit, x, y); + paintPar(pi, text, pit, x, y, true); y += text.getPar(pit).descent(); } } -- 2.39.2