mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-22 13:18:28 +00:00
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.
This commit is contained in:
parent
a48efa03b1
commit
201c95a76e
10
src/Row.cpp
10
src/Row.cpp
@ -27,6 +27,7 @@
|
|||||||
#include "support/lassert.h"
|
#include "support/lassert.h"
|
||||||
#include "support/lstrings.h"
|
#include "support/lstrings.h"
|
||||||
#include "support/lyxlib.h"
|
#include "support/lyxlib.h"
|
||||||
|
#include "support/textutils.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
@ -203,14 +204,13 @@ bool Row::Element::splitAt(int const width, int next_width, bool force,
|
|||||||
|
|
||||||
void Row::Element::rtrim()
|
void Row::Element::rtrim()
|
||||||
{
|
{
|
||||||
if (type != STRING)
|
if (type != STRING || str.empty() || !isSpace(str.back()))
|
||||||
return;
|
return;
|
||||||
/* This is intended for strings that have been created by splitAt.
|
/* This is intended for strings that have been created by splitAt.
|
||||||
* They may have trailing spaces, but they are not counted in the
|
* If There is a trailing space, we remove it and decrease endpos,
|
||||||
* string length (QTextLayout feature, actually). We remove them,
|
* since spaces at row break are invisible.
|
||||||
* and decrease endpos, since spaces at row break are invisible.
|
|
||||||
*/
|
*/
|
||||||
str = support::rtrim(str);
|
str.pop_back();
|
||||||
endpos = pos + str.length();
|
endpos = pos + str.length();
|
||||||
dim.wid = nspc_wid;
|
dim.wid = nspc_wid;
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
#include "support/convert.h"
|
#include "support/convert.h"
|
||||||
#include "support/debug.h"
|
#include "support/debug.h"
|
||||||
#include "support/lassert.h"
|
#include "support/lassert.h"
|
||||||
#include "support/lstrings.h" // for breakString_helper with qt4
|
|
||||||
#include "support/lyxlib.h"
|
#include "support/lyxlib.h"
|
||||||
|
#include "support/textutils.h"
|
||||||
|
|
||||||
#define DISABLE_PMPROF
|
#define DISABLE_PMPROF
|
||||||
#include "support/pmprof.h"
|
#include "support/pmprof.h"
|
||||||
@ -411,7 +411,13 @@ TextLayoutHelper::TextLayoutHelper(docstring const & s, bool isrtl, bool naked)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Now translate the string character-by-character.
|
// Now translate the string character-by-character.
|
||||||
|
bool was_space = false;
|
||||||
for (char_type const c : s) {
|
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
|
// Remember the QString index at this point
|
||||||
pos2qpos_.push_back(qstr.size());
|
pos2qpos_.push_back(qstr.size());
|
||||||
// Performance: UTF-16 characters are easier
|
// 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.
|
// If the line is not the last one, trailing space is always omitted.
|
||||||
int nspc_wid = wid;
|
int nspc_wid = wid;
|
||||||
// For the last line, compute the width without trailing space
|
// For the last line, compute the width without trailing space
|
||||||
if (i + 1 == tl.lineCount()) {
|
if (i + 1 == tl.lineCount() && !s.empty() && isSpace(s.back())
|
||||||
// trim_pos points to the last character that is not a space
|
&& line.textStart() <= tlh.pos2qpos(s.size() - 1))
|
||||||
auto trim_pos = s.find_last_not_of(from_ascii(" "));
|
nspc_wid = iround(line.cursorToX(tlh.pos2qpos(s.size() - 1)));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
// With some monospace fonts, the value of horizontalAdvance()
|
// With some monospace fonts, the value of horizontalAdvance()
|
||||||
// can be wrong with Qt4. One hypothesis is that the invisible
|
// can be wrong with Qt4. One hypothesis is that the invisible
|
||||||
// characters that we use are given a non-null width.
|
// 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
|
// 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 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
|
#endif
|
||||||
breaks.emplace_back(epos - pos, wid, nspc_wid);
|
breaks.emplace_back(epos - pos, wid, nspc_wid);
|
||||||
pos = epos;
|
pos = epos;
|
||||||
|
@ -1507,18 +1507,11 @@ int countExpanders(docstring const & str)
|
|||||||
// Numbers of characters that are expanded by inter-word spacing. These
|
// Numbers of characters that are expanded by inter-word spacing. These
|
||||||
// characters are spaces, except for characters 09-0D which are treated
|
// characters are spaces, except for characters 09-0D which are treated
|
||||||
// specially. (From a combination of testing with the notepad found in qt's
|
// specially. (From a combination of testing with the notepad found in qt's
|
||||||
// examples, and reading the source code.) In addition, consecutive spaces
|
// examples, and reading the source code.)
|
||||||
// only count as one expander.
|
|
||||||
bool wasspace = false;
|
|
||||||
int nexp = 0;
|
int nexp = 0;
|
||||||
for (char_type c : str)
|
for (char_type c : str)
|
||||||
if (c > 0x0d && isSpace(c)) {
|
if (c > 0x0d && isSpace(c))
|
||||||
if (!wasspace) {
|
|
||||||
++nexp;
|
++nexp;
|
||||||
wasspace = true;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
wasspace = false;
|
|
||||||
return nexp;
|
return nexp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user