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;
 }
 

Reply via email to