]> git.lyx.org Git - lyx.git/commitdiff
The speed patch: redraw only rows that have changed
authorMartin Vermeer <martin.vermeer@hut.fi>
Fri, 30 Dec 2005 19:02:52 +0000 (19:02 +0000)
committerMartin Vermeer <martin.vermeer@hut.fi>
Fri, 30 Dec 2005 19:02:52 +0000 (19:02 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@10692 a592a061-630c-0410-9148-cb99ea01b6c8

src/ChangeLog
src/RowList_fwd.h
src/paragraph.C
src/paragraph.h
src/rowpainter.C

index 85313927c06d361c9c158ab06524d4943d096278..58d78eb6d2f5692bc8353d95126c416e9aeb3a2a 100644 (file)
@@ -1,3 +1,12 @@
+2005-12-30  Martin Vermeer  <martin.vermeer@hut.fi>
+
+       * 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  <Georg.Baum@post.rwth-aachen.de>
 
        * version.C.in: Use PACKAGE_VERSION instead of VERSION
index c1a4de1cf1ff6c9c1e62e78a5501beaf9e4c62bf..55e22ab1e2ccb1bc92878720c9f79d5c2bc53e8b 100644 (file)
@@ -15,6 +15,7 @@
 #include "lyxrow.h"
 
 #include <vector>
+#include <map>
 
 /**
  * Each paragraph is broken up into a number of rows on the screen.
@@ -22,5 +23,7 @@
  * downwards.
  */
 typedef std::vector<Row> RowList;
+///
+typedef std::map<lyx::size_type, lyx::size_type> RowSignature;
 
 #endif
index 6588be1934a6281c954aae2aefbcceb556008241..227568b43f2067155a02c48d60358c590768753c 100644 (file)
@@ -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_;
index 13c99ca873527bec4efddf25eb3b39fb9e9dad43..9cb720cfb704d7b624b1dcef0cd7cdb79cb9c31e 100644 (file)
@@ -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_;
        /**
index 75a8f1fb1fbead05e300c339100c27c3dcb05ed5..91543fa30e2d46ba72df6284420c25433d366116 100644 (file)
@@ -40,6 +40,8 @@
 
 #include "support/textutils.h"
 
+#include <boost/crc.hpp>
+
 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<BufferView *>(&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();
        }
 }