From f7dde3d7748e3bbd4b3f0fbd1979dc04fb7c6dae Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Tue, 31 Aug 2021 15:58:56 +0200 Subject: [PATCH] Handle the case where breakAt cuts after trailing space In this case, the extra element returned should empty but valid. The row flag BreakAfter is set to indicate that we have a break there (this principle will be used more generally in a forthcoming commit). To detect that we cut at the trailing space, it is necessary to rely on the difference between QTextLine::horizontalAdvance() and QTextLine::naturalTextWidth() when the flag QTextOption::IncludeTrailingSpaces is used: the trailing space is taken into account in the later, but not in the former. Somme comments have been added to make code intent clearer. --- src/Row.cpp | 18 ++++++++++++++---- src/TextMetrics.cpp | 3 ++- src/frontends/qt/GuiFontMetrics.cpp | 10 ++++++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/Row.cpp b/src/Row.cpp index 6e975a5a65..38dbb85696 100644 --- a/src/Row.cpp +++ b/src/Row.cpp @@ -142,13 +142,19 @@ Row::Element Row::Element::splitAt(int w, bool force) dim.wid = w; int const i = fm.breakAt(str, dim.wid, isRTL(), force); if (i != -1) { + //Create a second row element to return Element ret(STRING, pos + i, font, change); ret.str = str.substr(i); ret.endpos = ret.pos + ret.str.length(); + // Copy the after flags of the original element to the second one. ret.row_flags = row_flags & (CanBreakInside | AfterFlags); + + // Now update ourselves str.erase(i); endpos = pos + i; - //lyxerr << "breakAt(" << w << ") Row element Broken at " << x << "(w(str)=" << fm.width(str) << "): e=" << *this << endl; + // Row should be broken after the original element + row_flags = (row_flags & ~AfterFlags) | BreakAfter; + //LYXERR0("breakAt(" << w << ") Row element Broken at " << w << "(w(str)=" << fm.width(str) << "): e=" << *this); return ret; } @@ -251,7 +257,7 @@ ostream & operator<<(ostream & os, Row::Element const & e) os << "INVALID: "; break; } - os << "width=" << e.full_width(); + os << "width=" << e.full_width() << ", row_flags=" << e.row_flags; return os; } @@ -522,7 +528,7 @@ Row::Elements Row::shortenIfNeeded(int const w, int const next_width) * break-up. */ Element remainder = brk.splitAt(min(w - wid_brk, brk.dim.wid - 2), !word_wrap); - if (remainder.isValid()) { + if (brk.row_flags & BreakAfter) { /* if this element originally did not cause a row overflow * in itself, and the remainder of the row would still be * too large after breaking, then we will have issues in @@ -544,7 +550,11 @@ Row::Elements Row::shortenIfNeeded(int const w, int const next_width) *cit_brk = brk; dim_.wid = wid_brk + brk.dim.wid; // If there are other elements, they should be removed. - return splitFrom(elements_, next(cit_brk, 1), remainder); + // remainder can be empty when splitting at trailing space + if (remainder.str.empty()) + return splitFrom(elements_, next(cit_brk, 1)); + else + return splitFrom(elements_, next(cit_brk, 1), remainder); } } diff --git a/src/TextMetrics.cpp b/src/TextMetrics.cpp index c7e84f614a..37894f61db 100644 --- a/src/TextMetrics.cpp +++ b/src/TextMetrics.cpp @@ -1157,7 +1157,8 @@ RowList TextMetrics::breakParagraph(Row const & bigrow) const // Add a new next element on the pile if (next_elt.isValid()) { // do as if we inserted this element in the original row - fcit.put(next_elt); + if (!next_elt.str.empty()) + fcit.put(next_elt); need_new_row = true; } } diff --git a/src/frontends/qt/GuiFontMetrics.cpp b/src/frontends/qt/GuiFontMetrics.cpp index 56ed676904..47537ae0a3 100644 --- a/src/frontends/qt/GuiFontMetrics.cpp +++ b/src/frontends/qt/GuiFontMetrics.cpp @@ -525,6 +525,9 @@ GuiFontMetrics::breakAt_helper(docstring const & s, int const x, QTextOption to; to.setWrapMode(force ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::WordWrap); + // Let QTextLine::naturalTextWidth() account for trailing spaces + // (horizontalAdvance() still does not). + to.setFlags(QTextOption::IncludeTrailingSpaces); tl.setTextOption(to); tl.beginLayout(); QTextLine line = tl.createLine(); @@ -557,8 +560,11 @@ GuiFontMetrics::breakAt_helper(docstring const & s, int const x, --len; LASSERT(len > 0 || qlen == 0, /**/); #endif - // Do not cut is the string is already short enough - if (len == static_cast(s.length())) { + // Do not cut is the string is already short enough. We rely on + // naturalTextWidth() to catch the case where we cut at the trailing + // space. + if (len == static_cast(s.length()) + && line.naturalTextWidth() <= x) { len = -1; #if QT_VERSION < 0x050000 // With some monospace fonts, the value of horizontalAdvance() -- 2.39.5