commit 24648404b3c85015584b1ca127e257cbecf3342d
Author: Jean-Marc Lasgouttes <[email protected]>
Date: Sun Oct 23 20:52:01 2016 +0200
Work around issues with Qt5 and Arabic text
This fixes two particular problems
* with Qt5, it seems that QFontMetrics::width does not return the
correct value for some Arabic text; this patch uses QTextLayout
instead to compute a string width
* Likewise, the undocumented layout flags TextForceRightToLeft and
TextForceLeftToRight do not work with Arabic text; this patch uses
unicode override characters instead.
It might be that the two issues are related. In any case, they do not
happen with latin text where right-to-left direction is enforced. And
they do not happen with Qt4.
Additionally, remove some dead code in GuiFontMetrics::pos2x().
Fixes bug #10436.
(cherry picked from commit e832d2e90f300afb1b1255a486e56d059b2dfab7)
---
src/frontends/qt4/GuiFontMetrics.cpp | 40 +++++++++++++++++++++++++++------
1 files changed, 32 insertions(+), 8 deletions(-)
diff --git a/src/frontends/qt4/GuiFontMetrics.cpp
b/src/frontends/qt4/GuiFontMetrics.cpp
index eade8cc..74ed392 100644
--- a/src/frontends/qt4/GuiFontMetrics.cpp
+++ b/src/frontends/qt4/GuiFontMetrics.cpp
@@ -146,7 +146,16 @@ int GuiFontMetrics::width(docstring const & s) const
int * pw = strwidth_cache_[qba];
if (pw)
return *pw;
- int w = metrics_.width(toqstr(s));
+ // For some reason QMetrics::width returns a wrong value with Qt5
+ // int w = metrics_.width(toqstr(s));
+ QTextLayout tl;
+ tl.setText(toqstr(s));
+ tl.setFont(font_);
+ tl.beginLayout();
+ QTextLine line = tl.createLine();
+ tl.endLayout();
+ int w = int(line.naturalTextWidth());
+
strwidth_cache_.insert(qba, new int(w), qba.size());
return w;
}
@@ -196,8 +205,6 @@ GuiFontMetrics::getTextLayout(docstring const & s, QFont
font,
int GuiFontMetrics::pos2x(docstring const & s, int const pos, bool const rtl,
double const wordspacing) const
{
- QFont copy = font_;
- copy.setWordSpacing(wordspacing);
QTextLayout const & tl = getTextLayout(s, font_, rtl, wordspacing);
return static_cast<int>(tl.lineForTextPosition(pos).cursorToX(pos));
}
@@ -228,10 +235,27 @@ bool GuiFontMetrics::breakAt(docstring & s, int & x, bool
const rtl, bool const
*/
// Unicode character ZERO WIDTH NO-BREAK SPACE
QChar const zerow_nbsp(0xfeff);
- tl.setText(zerow_nbsp + toqstr(s) + zerow_nbsp);
- tl.setFont(font_);
+ QString str = zerow_nbsp + toqstr(s) + zerow_nbsp;
+#if 1
+ /* Use unicode override characters to enforce drawing direction
+ * Source: http://www.iamcal.com/understanding-bidirectional-text/
+ */
+ if (rtl)
+ // Right-to-left override: forces to draw text right-to-left
+ str = QChar(0x202E) + str;
+ else
+ // Left-to-right override: forces to draw text left-to-right
+ str = QChar(0x202D) + str;
+ int const offset = 2;
+#else
+ // Alternative version that breaks with Qt5 and arabic text (#10436)
// Note that both setFlags and the enums are undocumented
tl.setFlags(rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight);
+ int const offset = 1;
+#endif
+
+ tl.setText(str);
+ tl.setFont(font_);
QTextOption to;
to.setWrapMode(force ? QTextOption::WrapAnywhere :
QTextOption::WordWrap);
tl.setTextOption(to);
@@ -240,11 +264,11 @@ bool GuiFontMetrics::breakAt(docstring & s, int & x, bool
const rtl, bool const
line.setLineWidth(x);
tl.createLine();
tl.endLayout();
- if ((force && line.textLength() == 1) || int(line.naturalTextWidth()) >
x)
+ if ((force && line.textLength() == offset) ||
int(line.naturalTextWidth()) > x)
return false;
x = int(line.naturalTextWidth());
- // The -1 is here to account for the leading zerow_nbsp.
- s = s.substr(0, line.textLength() - 1);
+ // The offset is here to account for the extra leading characters.
+ s = s.substr(0, line.textLength() - offset);
return true;
}