The branch, rowpainter2, has been updated.

- Log -----------------------------------------------------------------

commit f65f3adbf73283a288f5d186b51b6b98c9ecb51d
Author: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date:   Sun Jul 19 01:22:10 2015 +0200

    Do not break row elements at spaces
    
    The goal of this commit is to make painting faster by reducing the
    number of strings to paint. To this end, it is necessary to include
    spaces in row elements.
    
    Also importantly, this commit should fix existing problems with line
    breaking in chinese text.
    
    * TextMetrics::breakRow: do not do anything special for word separators.
    
    * Row::add: when adding a character to a row element, keep the string
      width updated. If need be, it is possible to tweak this by updating
      every 10 characters, for example.
    
    * GuiFontMetrics::breakAt (new): use QTextLayout to break text either
      at word boundary or at an arbitrary width.
    
    * Row::Element::breakAt: use the above method.
    
    * Row::shortenIfNeeded: simplify now that because there is no need for
      handling separator elements. This will be taken care of by the
      improved breakAt.
    
    Two things remain to be done:
    
    * remove all traces of separator row element
    
    * re-implement text justification.

diff --git a/src/Row.cpp b/src/Row.cpp
index 57f02e2..5118f17 100644
--- a/src/Row.cpp
+++ b/src/Row.cpp
@@ -24,6 +24,7 @@
 
 #include "support/debug.h"
 #include "support/lassert.h"
+#include "support/lstrings.h"
 #include "support/lyxalgo.h"
 
 #include <ostream>
@@ -32,6 +33,7 @@ using namespace std;
 
 namespace lyx {
 
+using support::rtrim;
 using frontend::FontMetrics;
 
 double Row::Element::pos2x(pos_type const i) const
@@ -96,24 +98,21 @@ pos_type Row::Element::x2pos(int &x) const
 }
 
 
-bool Row::Element::breakAt(int w)
+bool Row::Element::breakAt(int w, bool force)
 {
        if (type != STRING || dim.wid <= w)
                return false;
 
        bool const rtl = font.isVisibleRightToLeft();
-       if (rtl)
-               w = dim.wid - w;
-       pos_type new_pos = x2pos(w);
-       if (new_pos == pos)
-               return false;
-       str = str.substr(0, new_pos - pos);
-       if (rtl)
-               dim.wid -= w;
-       else
-               dim.wid = w;
-       endpos = new_pos;
-       return true;
+       FontMetrics const & fm = theFontMetrics(font);
+       int x = w;
+       if(fm.breakAt(str, x, rtl, force)) {
+               dim.wid = x;
+               endpos = pos + str.length();
+               //lyxerr << "breakAt(" << w << ")  Row element Broken at " << x 
<< "(w(str)=" << fm.width(str) << "): e=" << *this << endl;
+               return true;
+       }
+       return false;
 }
 
 
@@ -278,6 +277,7 @@ void Row::finalizeLast()
        elt.final = true;
 
        if (elt.type == STRING) {
+               dim_.wid -= elt.dim.wid;
                elt.dim.wid = theFontMetrics(elt.font).width(elt.str);
                dim_.wid += elt.dim.wid;
        }
@@ -304,8 +304,11 @@ void Row::add(pos_type const pos, char_type const c,
                Element e(STRING, pos, f, ch);
                elements_.push_back(e);
        }
+       dim_.wid -= back().dim.wid;
        back().str += c;
        back().endpos = pos + 1;
+       back().dim.wid = theFontMetrics(back().font).width(back().str);
+       dim_.wid += back().dim.wid;
 }
 
 
@@ -357,33 +360,17 @@ void Row::shortenIfNeeded(pos_type const keep, int const 
w)
 {
        if (empty() || width() <= w)
                return;
-
        Elements::iterator const beg = elements_.begin();
        Elements::iterator const end = elements_.end();
-       Elements::iterator last_sep = elements_.end();
-       int last_width = 0;
        int wid = left_margin;
 
        Elements::iterator cit = beg;
        for ( ; cit != end ; ++cit) {
-               if (cit->type == SEPARATOR && cit->pos >= keep) {
-                       last_sep = cit;
-                       last_width = wid;
-               }
-               if (wid + cit->dim.wid > w)
+               if (cit->endpos >= keep && wid + cit->dim.wid > w)
                        break;
                wid += cit->dim.wid;
        }
 
-       if (last_sep != end) {
-               // We have found a suitable separator. This is the
-               // common case.
-               end_ = last_sep->endpos;
-               dim_.wid = last_width;
-               elements_.erase(last_sep, end);
-               return;
-       }
-
        if (cit == end) {
                // This should not happen since the row is too long.
                LYXERR0("Something is wrong cannot shorten row: " << *this);
@@ -397,23 +384,41 @@ void Row::shortenIfNeeded(pos_type const keep, int const 
w)
                wid -= cit->dim.wid;
        }
 
+       // Try to break this row cleanly (at word boundary)
+       if (cit->breakAt(w - wid, false)) {
+               end_ = cit->endpos;
+               // after breakAt, there may be spaces at the end of the
+               // string, but they are not counted in the string length
+               // (qtextlayout feature, actually). We remove them, but do not
+               // change the endo of the row, since the spaces at row break
+               // are invisible.
+               cit->str = rtrim(cit->str);
+               cit->endpos = cit->pos + cit->str.length();
+               dim_.wid = wid + cit->dim.wid;
+               // If there are other elements, they should be removed.
+               elements_.erase(next(cit, 1), end);
+               return;
+       }
+
        if (cit != beg) {
-               // There is no separator, but several elements (probably
-               // insets) have been added. We can cut at this place.
+               // There is no separator, but several elements have been
+               // added. We can cut right here.
                end_ = cit->pos;
                dim_.wid = wid;
                elements_.erase(cit, end);
                return;
        }
 
-       /* If we are here, it means that we have not found a separator
-        * to shorten the row. There is one case where we can do
-        * something: when we have one big string, maybe with some
-        * other things after it.
+       /* If we are here, it means that we have not found a separator to
+        * shorten the row. Let's try to break it again, but not at word
+        * boundary this time.
         */
-       if (cit->breakAt(w - left_margin)) {
+       if (cit->breakAt(w - wid, true)) {
                end_ = cit->endpos;
-               dim_.wid = left_margin + cit->dim.wid;
+               // See comment above.
+               cit->str = rtrim(cit->str);
+               cit->endpos = cit->pos + cit->str.length();
+               dim_.wid = wid + cit->dim.wid;
                // If there are other elements, they should be removed.
                elements_.erase(next(cit, 1), end);
        }
diff --git a/src/Row.h b/src/Row.h
index 9039ff8..490aa6b 100644
--- a/src/Row.h
+++ b/src/Row.h
@@ -86,10 +86,12 @@ public:
                 *  adjusted to the actual pixel position.
                */
                pos_type x2pos(int &x) const;
-               /** Break the element if possible, so that its width is
-                * less then \param w. Returns true on success.
+               /** Break the element if possible, so that its width is less
+                * than \param w. Returns true on success. When \param force
+                * is true, the string is cut at any place, other wise it
+                * respects the row breaking rules of characters.
                 */
-               bool breakAt(int w);
+               bool breakAt(int w, bool force);
 
                // Returns the position on left side of the element.
                pos_type left_pos() const;
diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp
index 2f314b5..c3017d8 100644
--- a/src/TextMetrics.cpp
+++ b/src/TextMetrics.cpp
@@ -819,7 +819,7 @@ void TextMetrics::breakRow(Row & row, int const 
right_margin, pit_type const pit
        // or the end of the par, then build a representation of the row.
        pos_type i = pos;
        FontIterator fi = FontIterator(*this, par, pit, pos);
-       while (i < end && row.width() < width) {
+       while (i < end && row.width() <= width) {
                char_type c = par.getChar(i);
                // The most special cases are handled first.
                if (par.isInset(i)) {
@@ -837,13 +837,6 @@ void TextMetrics::breakRow(Row & row, int const 
right_margin, pit_type const pit
                        int const add = max(fm.width(par.layout().labelsep),
                                            labelEnd(pit) - row.width());
                        row.addSpace(i, add, *fi, par.lookupChange(i));
-               } else if (par.isLineSeparator(i)) {
-                       // In theory, no inset has this property. If
-                       // this is done, a new addSeparator which
-                       // takes an inset as parameter should be
-                       // added.
-                       LATTEST(!par.isInset(i));
-                       row.addSeparator(i, c, *fi, par.lookupChange(i));
                } else if (c == '\t')
                        row.addSpace(i, theFontMetrics(*fi).width(from_ascii("  
  ")),
                                     *fi, par.lookupChange(i));
@@ -905,6 +898,7 @@ void TextMetrics::breakRow(Row & row, int const 
right_margin, pit_type const pit
 
        // make sure that the RTL elements are in reverse ordering
        row.reverseRTL(is_rtl);
+       //LYXERR0("breakrow: row is " << row);
 }
 
 
diff --git a/src/frontends/FontMetrics.h b/src/frontends/FontMetrics.h
index 53f57a2..84000d1 100644
--- a/src/frontends/FontMetrics.h
+++ b/src/frontends/FontMetrics.h
@@ -93,6 +93,14 @@ public:
         * the offset x is updated to match the closest position in the string.
         */
        virtual int x2pos(docstring const & s, int & x, bool rtl) const = 0;
+       /**
+        * Break string at width at most x.
+        * \return true if successful
+        * \param rtl is true for right-to-left layout
+        * \param force is false for breaking at word separator, true for
+        *   arbitrary position.
+        */
+       virtual bool breakAt(docstring & s, int & x, bool rtl, bool force) 
const = 0;
        /// return char dimension for the font.
        virtual Dimension const dimension(char_type c) const = 0;
        /**
diff --git a/src/frontends/qt4/GuiFontMetrics.cpp 
b/src/frontends/qt4/GuiFontMetrics.cpp
index b488b68..804813a 100644
--- a/src/frontends/qt4/GuiFontMetrics.cpp
+++ b/src/frontends/qt4/GuiFontMetrics.cpp
@@ -183,6 +183,31 @@ int GuiFontMetrics::x2pos(docstring const & s, int & x, 
bool const rtl) const
 }
 
 
+bool GuiFontMetrics::breakAt(docstring & s, int & x, bool const rtl, bool 
const force) const
+{
+       if (s.empty())
+               return false;
+       QTextLayout tl;
+       tl.setText(toqstr(s));
+       tl.setFont(font_);
+       // Note that both setFlags and the enums are undocumented
+       tl.setFlags(rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight);
+       QTextOption to;
+       to.setWrapMode(force ? QTextOption::WrapAnywhere : 
QTextOption::WordWrap);
+       tl.setTextOption(to);
+       tl.beginLayout();
+       QTextLine line = tl.createLine();
+       line.setLineWidth(x);
+       tl.createLine();
+       tl.endLayout();
+       if (int(line.naturalTextWidth()) > x)
+               return false;
+       x = int(line.naturalTextWidth());
+       s = s.substr(0, line.textLength());
+       return true;
+}
+
+
 void GuiFontMetrics::rectText(docstring const & str,
        int & w, int & ascent, int & descent) const
 {
diff --git a/src/frontends/qt4/GuiFontMetrics.h 
b/src/frontends/qt4/GuiFontMetrics.h
index 7555929..bc6b24a 100644
--- a/src/frontends/qt4/GuiFontMetrics.h
+++ b/src/frontends/qt4/GuiFontMetrics.h
@@ -45,6 +45,7 @@ public:
        virtual int signedWidth(docstring const & s) const;
        virtual int pos2x(docstring const & s, int pos, bool rtl) const;
        virtual int x2pos(docstring const & s, int & x, bool rtl) const;
+       virtual bool breakAt(docstring & s, int & x, bool rtl, bool force) 
const;
        virtual Dimension const dimension(char_type c) const;
 
        virtual void rectText(docstring const & str,

-----------------------------------------------------------------------

Summary of changes:
 src/Row.cpp                          |   81 ++++++++++++++++++----------------
 src/Row.h                            |    8 ++-
 src/TextMetrics.cpp                  |   10 +---
 src/frontends/FontMetrics.h          |    8 +++
 src/frontends/qt4/GuiFontMetrics.cpp |   25 ++++++++++
 src/frontends/qt4/GuiFontMetrics.h   |    1 +
 6 files changed, 84 insertions(+), 49 deletions(-)


hooks/post-receive
-- 
Repository for new features

Reply via email to