On Wed, Dec 21, 2005 at 01:46:53PM -0500, Bennett Helm wrote:
> On Dec 21, 2005, at 9:01 AM, Bennett Helm wrote:
> 
> >I haven't noticed any strange drawing issues.
> 
> I take that back. On occasion, when typing text into the middle of a  
> paragraph should result in the last word of that line being bumped to  
> the next line, it doesn't happen on screen, even though the next line  
> and subsequent lines are properly redrawn. A similar problem happens  
> (and not always in the same cases) with deleting: when deleting text  
> in a line should result in a word from the next line being brought  
> up, that word does appear in the current line, though the next line  
> still contains that word.
> 
> I hope that's clear. I haven't been able to see a pattern as to when  
> the problem occurs and when not. But it's frequent enough that you  
> should be able to reproduce it without much effort.

Clear enough. Jean-Marc has been expecting that the 'row signature' we
are using isn't discriminating enough, and now you seem to have run into
that.

Our row signature is

        rit->endpos() - rit->pos() + 1000 * y

which means: end-of-row - beginning-of-row + 1000 * vertical position of
row. The row beginning and end positions in characters from
start-of-paragraph, y in pixels from top of screen.

I expect that the pattern you see is: the word that gets pushed to the
next line is the same length as the word getting pushed to the 'next
next' line. I can reproduce that. (endpos - pos) remains unchanged.

A good signature has the following properties:

1) it _never_ changes when the row does not change. (e.g., not when you
add characters above it in the paragraph.)
2) it _always_ changes when the row changes. On this, the current
signature is weak.

The best signature would be a checksum computed over the row content,
but designed such that, e.g., changing the order of the characters will
produce a different checksum. Such a checksum would be rather expensive
to compute.

We should think of a signature that is simple and cheap, but better than
this one.

BTW I did manage to extend the patch to include text inside insets.
Attached. You will see that there are still some rendering 'warts', but
I live in hope. The logic seems to be correct.

Please let me know if you get the intended speed-up, and if so, we'll
start ironing out the warts. Hopefully.

- Martin

PS I'll be out of the scenery over the extended Christmas weekend.

Index: RowList_fwd.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/RowList_fwd.h,v
retrieving revision 1.6
diff -u -p -r1.6 RowList_fwd.h
--- RowList_fwd.h       31 Jan 2005 16:29:38 -0000      1.6
+++ RowList_fwd.h       21 Dec 2005 20:34:02 -0000
@@ -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: paragraph.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/paragraph.C,v
retrieving revision 1.417
diff -u -p -r1.417 paragraph.C
--- paragraph.C 25 Nov 2005 14:40:34 -0000      1.417
+++ paragraph.C 21 Dec 2005 20:34:03 -0000
@@ -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=(Paragra
 
                rows_ = par.rows_;
                dim_ = par.dim_;
+               rowSignature_ = par.rowSignature_;
                layout_ = par.layout();
                text_ = par.text_;
                begin_of_body_ = par.begin_of_body_;
Index: paragraph.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/paragraph.h,v
retrieving revision 1.157
diff -u -p -r1.157 paragraph.h
--- paragraph.h 7 Sep 2005 10:36:59 -0000       1.157
+++ paragraph.h 21 Dec 2005 20:34:03 -0000
@@ -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: rowpainter.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/rowpainter.C,v
retrieving revision 1.159
diff -u -p -r1.159 rowpainter.C
--- rowpainter.C        2 Dec 2005 13:20:26 -0000       1.159
+++ rowpainter.C        21 Dec 2005 20:34:03 -0000
@@ -37,6 +37,7 @@
 #include "frontends/Painter.h"
 
 #include "insets/insettext.h"
+#include "insets/insetcollapsable.h"
 
 #include "support/textutils.h"
 
@@ -158,7 +159,8 @@ void RowPainter::paintInset(pos_type con
        pi.ltr_pos = (text_.bidi.level(pos) % 2 == 0);
        pi.erased_ = erased_ || isDeletedText(par_, pos);
        theCoords.insets().add(inset, int(x_), yo_);
-       inset->drawSelection(pi, int(x_), yo_);
+       if (bv_.refresh())
+               inset->drawSelection(pi, int(x_), yo_);
        inset->draw(pi, int(x_), yo_);
        x_ += inset->width();
 }
@@ -719,7 +721,8 @@ void paintPar
        static NullPainter nop;
        static PainterInfo nullpi(pi.base.bv, nop);
        int const ww = pi.base.bv->workHeight();
-
+       bool repaintAll = pi.base.bv->refresh();
+       
        Paragraph const & par = text.paragraphs()[pit];
 
        RowList::const_iterator const rb = par.rows().begin();
@@ -734,15 +737,70 @@ void paintPar
                RowPainter rp(inside ? pi : nullpi, text, pit, *rit, x, y);
 
                y += rit->descent();
-               rp.paintAppendix();
-               rp.paintDepthBar();
-               rp.paintChangeBar();
-               if (rit == rb)
-                       rp.paintFirst();
-               if (rit + 1 == re)
-                       rp.paintLast();
-               rp.paintText();
+
+               // Row signature; has row changed since last paint?
+               lyx::size_type const row_sig 
+                       = rit->endpos() - rit->pos() + 1000 * y;
+
+               // The following code figures out if the cursor is inside
+               // an inset _on this row_.
+               bool cur_in_inset_in_row(false);
+               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)) {
+                               cur_in_inset_in_row = true;
+                               break;
+                       }
+               }
+
+               // 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
+               lyx::size_type rowno = std::distance(rit, rb);
+               if (repaintAll || par.rowSignature()[rowno] != row_sig 
+                          || cur_in_inset_in_row) {
+                       // Add to row signature cache
+                       par.rowSignature()[rowno] = row_sig;
+
+                       // Signals if this row contains a single open inset
+                       // and nothing more
+                       bool openInsetOnly = (rit->endpos() - rit->pos() == 1)
+                           && par.isInset(rit->pos())
+                           && par.getInset(rit->pos())->isTextInset();
+                       if (openInsetOnly) {
+                               InsetCollapsable const * in =
+                                  static_cast<InsetCollapsable const 
*>(par.getInset(rit->pos()));
+                               openInsetOnly = in->isOpen();
+                       }
+
+                       // Clear background of this row 
+                       // (if whole screen background was not cleared)
+                       if (!repaintAll && !openInsetOnly) {
+                               // Try to keep row background inside inset
+                               // frame (how?)
+                               int w = pi.base.bv->workWidth() - 30;
+                               int ht = rit->ascent() + rit->descent();
+                               pi.pain.fillRectangle(x, y - ht, w, ht,
+                                   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();
+               }
        }
+       //lyxerr << "." << endl;
 }
 
 } // namespace anon
@@ -752,22 +810,28 @@ void paintText(BufferView const & bv, 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);
+       // Should the whole screen, including insets, be refreshed?
+       bv.refresh(select || !vi.singlepar);
+       if (bv.refresh()) {
+               // Clear background 
+               // (Delegated to rows if no forced screen refresh)
+               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();
+               Paragraph const & par = text->getPar(pit);
+               yy += par.ascent();
                paintPar(pi, *bv.text(), pit, 0, yy);
-               yy += text->getPar(pit).descent();
+               yy += par.descent();
        }
 
        // Cache one paragraph above and one below
Index: BufferView.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/BufferView.C,v
retrieving revision 1.264
diff -u -p -r1.264 BufferView.C
--- BufferView.C        1 Dec 2005 10:28:47 -0000       1.264
+++ BufferView.C        21 Dec 2005 20:34:03 -0000
@@ -369,6 +369,18 @@ void BufferView::putSelectionAt(DocItera
 }
 
 
+bool const BufferView::refresh() const
+{ 
+       return pimpl_->refresh(); 
+}
+
+       
+void const BufferView::refresh(bool r) const
+{ 
+       pimpl_->refresh(r);
+}
+
+
 LCursor & BufferView::cursor()
 {
        return pimpl_->cursor_;
Index: BufferView.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/BufferView.h,v
retrieving revision 1.189
diff -u -p -r1.189 BufferView.h
--- BufferView.h        1 Dec 2005 10:28:47 -0000       1.189
+++ BufferView.h        21 Dec 2005 20:34:04 -0000
@@ -198,7 +198,10 @@ public:
         */
        void putSelectionAt(DocIterator const & cur,
                int length, bool backwards);
-
+       ///
+       bool const refresh() const;
+       ///
+       void const refresh(bool r) const;
 
 private:
        ///
Index: BufferView_pimpl.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/BufferView_pimpl.h,v
retrieving revision 1.129
diff -u -p -r1.129 BufferView_pimpl.h
--- BufferView_pimpl.h  7 Nov 2005 15:06:42 -0000       1.129
+++ BufferView_pimpl.h  21 Dec 2005 20:34:04 -0000
@@ -103,6 +103,10 @@ public:
        FuncStatus getStatus(FuncRequest const & cmd);
        /// a function should be executed
        bool dispatch(FuncRequest const & ev);
+       ///
+       bool refresh() { return refresh_; }
+       ///
+       void refresh(bool r) {refresh_ = r; }
 private:
        /// An error list (replaces the error insets)
        ErrorList errorlist_;
@@ -189,7 +193,8 @@ private:
        int offset_ref_;
        ///
        ViewMetricsInfo metrics(bool singlepar = false);
-
+       /// Working variable indicating a full screen refresh
+       mutable bool refresh_;
 
 };
 #endif // BUFFERVIEW_PIMPL_H
Index: insets/insetcollapsable.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insetcollapsable.C,v
retrieving revision 1.281
diff -u -p -r1.281 insetcollapsable.C
--- insets/insetcollapsable.C   16 Dec 2005 12:48:18 -0000      1.281
+++ insets/insetcollapsable.C   21 Dec 2005 20:34:05 -0000
@@ -140,15 +140,20 @@ void InsetCollapsable::metrics(MetricsIn
                        InsetText::metrics(mi, textdim_);
                        bool oldopeninlined = openinlined_;
                        openinlined_ = (textdim_.wid + dim.wid <= 
mi.base.textwidth);
-                       if (openinlined_ != oldopeninlined)
+                       if (openinlined_ != oldopeninlined) {
                                InsetText::metrics(mi, textdim_);
+                               mi.base.bv->update();
+                       }
                        if (openinlined_) {
                                dim.wid += textdim_.wid;
                                dim.des = max(dim.des - textdim_.asc + dim.asc, 
textdim_.des);
                                dim.asc = textdim_.asc;
                        } else {
                                dim.des += textdim_.height() + 
TEXT_TO_BOTTOM_OFFSET;
-                               dim.wid = max(dim.wid, textdim_.wid);
+                               // Fixed width needed across refreshes, cf.
+                               // rowpainter's selective row refresh
+                               // mechanism
+                               dim.wid = mi.base.textwidth;
                        }
                }
        }
Index: insets/insettext.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/insets/insettext.C,v
retrieving revision 1.622
diff -u -p -r1.622 insettext.C
--- insets/insettext.C  21 Oct 2005 09:55:23 -0000      1.622
+++ insets/insettext.C  21 Dec 2005 20:34:05 -0000
@@ -192,6 +192,7 @@ void InsetText::draw(PainterInfo & pi, i
        // update our idea of where we are
        setPosCache(pi, x, y);
 
+       text_.background_color_ = backgroundColor();
        text_.draw(pi, x + border_, y);
 
        if (drawFrame_) {

Attachment: pgpnD7CRJ8F9U.pgp
Description: PGP signature

Reply via email to