commit 201c95a76ea69fb5c6652b657b175db12bcd5e80
Author: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date:   Mon Jul 11 23:56:35 2022 +0200

    Handle multiple spaces at row break
    
    In order to work around the Qt row breaking algorithm, which considers
    multiple spaces as one at QTextLine break, we insert word_joiner unicode
    characters beteween each pair of spaces.
    
    The TextLayoutHelper class makes it easy to handle that.
    
    Update Row::Element::rtrim() to only remove one space at row end.
    
    Update support::countExpanders() to count all spaces, without special
    handling for consecutive ones.
    
    Fixes bug #10117.
---
 src/Row.cpp                         |   10 +++++-----
 src/frontends/qt/GuiFontMetrics.cpp |   30 ++++++++++++++----------------
 src/support/lstrings.cpp            |   13 +++----------
 3 files changed, 22 insertions(+), 31 deletions(-)

diff --git a/src/Row.cpp b/src/Row.cpp
index 1c17fb2..6edde19 100644
--- a/src/Row.cpp
+++ b/src/Row.cpp
@@ -27,6 +27,7 @@
 #include "support/lassert.h"
 #include "support/lstrings.h"
 #include "support/lyxlib.h"
+#include "support/textutils.h"
 
 #include <algorithm>
 #include <ostream>
@@ -203,14 +204,13 @@ bool Row::Element::splitAt(int const width, int 
next_width, bool force,
 
 void Row::Element::rtrim()
 {
-       if (type != STRING)
+       if (type != STRING || str.empty() || !isSpace(str.back()))
                return;
        /* This is intended for strings that have been created by splitAt.
-        * They may have trailing spaces, but they are not counted in the
-        * string length (QTextLayout feature, actually). We remove them,
-        * and decrease endpos, since spaces at row break are invisible.
+        * If There is a trailing space, we remove it and decrease endpos,
+        * since spaces at row break are invisible.
         */
-       str = support::rtrim(str);
+       str.pop_back();
        endpos = pos + str.length();
        dim.wid = nspc_wid;
 }
diff --git a/src/frontends/qt/GuiFontMetrics.cpp 
b/src/frontends/qt/GuiFontMetrics.cpp
index 7fe067b..3ee2702 100644
--- a/src/frontends/qt/GuiFontMetrics.cpp
+++ b/src/frontends/qt/GuiFontMetrics.cpp
@@ -20,8 +20,8 @@
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/lassert.h"
-#include "support/lstrings.h" // for breakString_helper with qt4
 #include "support/lyxlib.h"
+#include "support/textutils.h"
 
 #define DISABLE_PMPROF
 #include "support/pmprof.h"
@@ -411,7 +411,13 @@ TextLayoutHelper::TextLayoutHelper(docstring const & s, 
bool isrtl, bool naked)
 #endif
 
        // Now translate the string character-by-character.
+       bool was_space = false;
        for (char_type const c : s) {
+               // insert a word joiner character between consecutive spaces
+               bool const is_space = isSpace(c);
+               if (!naked && is_space && was_space)
+                       qstr += word_joiner;
+               was_space = is_space;
                // Remember the QString index at this point
                pos2qpos_.push_back(qstr.size());
                // Performance: UTF-16 characters are easier
@@ -599,27 +605,19 @@ GuiFontMetrics::breakString_helper(docstring const & s, 
int first_wid, int wid,
                // If the line is not the last one, trailing space is always 
omitted.
                int nspc_wid = wid;
                // For the last line, compute the width without trailing space
-               if (i + 1 == tl.lineCount()) {
-                       // trim_pos points to the last character that is not a 
space
-                       auto trim_pos = s.find_last_not_of(from_ascii(" "));
-                       if (trim_pos == docstring::npos)
-                               nspc_wid = 0;
-                       else if (trim_pos + 1 < s.length()) {
-                               int const num_spaces = s.length() - trim_pos - 
1;
-                               // find the position on the line before trailing
-                               // spaces. Remove 1 to account for the ending
-                               // non-breaking space of qs.
-                               nspc_wid = iround(line.cursorToX(line_epos - 
num_spaces - 1));
-                       }
-               }
+               if (i + 1 == tl.lineCount() && !s.empty() && isSpace(s.back())
+                   && line.textStart() <= tlh.pos2qpos(s.size() - 1))
+                       nspc_wid = iround(line.cursorToX(tlh.pos2qpos(s.size() 
- 1)));
 #else
                // With some monospace fonts, the value of horizontalAdvance()
                // can be wrong with Qt4. One hypothesis is that the invisible
                // characters that we use are given a non-null width.
                // FIXME: this is slower than it could be but we'll get rid of 
Qt4 anyway
-               docstring const ss = s.substr(pos, epos - pos);
+               docstring ss = s.substr(pos, epos - pos);
                int const wid = width(ss);
-               int const nspc_wid = i + 1 < tl.lineCount() ? width(rtrim(ss)) 
: wid;
+               if (!ss.empty() && isSpace(ss.back()))
+                       ss.pop_back();
+               int const nspc_wid = i + 1 < tl.lineCount() ? width(ss) : wid;
 #endif
                breaks.emplace_back(epos - pos, wid, nspc_wid);
                pos = epos;
diff --git a/src/support/lstrings.cpp b/src/support/lstrings.cpp
index 77c0115..d5b6dea 100644
--- a/src/support/lstrings.cpp
+++ b/src/support/lstrings.cpp
@@ -1507,18 +1507,11 @@ int countExpanders(docstring const & str)
        // Numbers of characters that are expanded by inter-word spacing.  These
        // characters are spaces, except for characters 09-0D which are treated
        // specially.  (From a combination of testing with the notepad found in 
qt's
-       // examples, and reading the source code.)  In addition, consecutive 
spaces
-       // only count as one expander.
-       bool wasspace = false;
+       // examples, and reading the source code.)
        int nexp = 0;
        for (char_type c : str)
-               if (c > 0x0d && isSpace(c)) {
-                       if (!wasspace) {
-                               ++nexp;
-                               wasspace = true;
-                       }
-               } else
-                       wasspace = false;
+               if (c > 0x0d && isSpace(c))
+                       ++nexp;
        return nexp;
 }
 
-- 
lyx-cvs mailing list
lyx-cvs@lists.lyx.org
http://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to