mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-11-22 10:00:33 +00:00
Better algorithm for forcing bidi drawing
The use of RLO/LRO overrides to force text orientation was really hackish and the way it was done caused dropped letters in Mac OS X (for some unknown reasons). This new approach is much cleaner, except that it relies on features not advertised in documentation but present at least from Qt 4.5 to Qt 5.3: * TextFlag enum values TextForceLeftToRight and TextForceRightToLeft, which are strong versions of QPainter::setLayoutDirection; they are passed as a parameter of QPainter::drawText. * QTextLayout::setFlags method, which is required to pass the above flags to QTextLayout. The unicode override method is still used to draw strings Mac OS X because, for some reason, the direction was not really enforced in this case.
This commit is contained in:
parent
bbe6e9f593
commit
f4fc035cf6
@ -109,10 +109,10 @@ public:
|
||||
graphics::Image const & image) = 0;
|
||||
|
||||
/** draw a string at position x, y (y is the baseline). The
|
||||
* text direction is deduced from \c str.
|
||||
* text direction is given by \c rtl.
|
||||
* \return the width of the drawn text.
|
||||
*/
|
||||
virtual int text(int x, int y, docstring const & str, FontInfo const & f) = 0;
|
||||
virtual int text(int x, int y, docstring const & str, FontInfo const & f, bool rtl = false) = 0;
|
||||
|
||||
/** draw a string at position x, y (y is the baseline). The
|
||||
* text direction is enforced by the \c Font.
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "insets/Inset.h"
|
||||
|
||||
#include "support/lassert.h"
|
||||
#include "support/lstrings.h"
|
||||
|
||||
#include <QTextLayout>
|
||||
|
||||
@ -148,9 +147,10 @@ namespace {
|
||||
void setTextLayout(QTextLayout & tl, docstring const & s, QFont const & font,
|
||||
bool const rtl)
|
||||
{
|
||||
QString const qs = toqstr(directedString(s, rtl));
|
||||
tl.setText(qs);
|
||||
tl.setText(toqstr(s));
|
||||
tl.setFont(font);
|
||||
// Note that both setFlags and the enums are undocumented
|
||||
tl.setFlags(rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight);
|
||||
tl.beginLayout();
|
||||
tl.createLine();
|
||||
tl.endLayout();
|
||||
@ -162,8 +162,7 @@ int GuiFontMetrics::pos2x(docstring const & s, int const pos, bool const rtl) co
|
||||
{
|
||||
QTextLayout tl;
|
||||
setTextLayout(tl, s, font_, rtl);
|
||||
// we take into account the unicode formatting characters
|
||||
return tl.lineForTextPosition(pos + 1).cursorToX(pos + 1);
|
||||
return tl.lineForTextPosition(pos).cursorToX(pos);
|
||||
}
|
||||
|
||||
|
||||
@ -172,13 +171,8 @@ int GuiFontMetrics::x2pos(docstring const & s, int & x, bool const rtl) const
|
||||
QTextLayout tl;
|
||||
setTextLayout(tl, s, font_, rtl);
|
||||
int pos = tl.lineForTextPosition(0).xToCursor(x);
|
||||
// take into account the unicode formatting characters
|
||||
if (pos > 0)
|
||||
--pos;
|
||||
if (pos > int(s.length()))
|
||||
pos = s.length();
|
||||
// correct x value to the actual cursor position.
|
||||
x = tl.lineForTextPosition(0).cursorToX(pos + 1);
|
||||
x = tl.lineForTextPosition(0).cursorToX(pos);
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,10 @@
|
||||
* Full author contact details are available in file CREDITS.
|
||||
*/
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#define USE_RTL_OVERRIDE 1
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "GuiPainter.h"
|
||||
@ -27,7 +31,6 @@
|
||||
#include "insets/Inset.h"
|
||||
|
||||
#include "support/lassert.h"
|
||||
#include "support/lstrings.h"
|
||||
#include "support/debug.h"
|
||||
|
||||
#include <QPixmapCache>
|
||||
@ -278,7 +281,7 @@ int GuiPainter::text(int x, int y, char_type c, FontInfo const & f)
|
||||
|
||||
|
||||
int GuiPainter::text(int x, int y, docstring const & s,
|
||||
FontInfo const & f)
|
||||
FontInfo const & f, bool const rtl)
|
||||
{
|
||||
//LYXERR0("text: x=" << x << ", s=" << s);
|
||||
if (s.empty())
|
||||
@ -304,8 +307,8 @@ int GuiPainter::text(int x, int y, docstring const & s,
|
||||
str = ' ' + str;
|
||||
#endif
|
||||
|
||||
QFont const & ff = getFont(f);
|
||||
GuiFontMetrics const & fm = getFontMetrics(f);
|
||||
QFont const & ff = getFont(f);
|
||||
GuiFontMetrics const & fm = getFontMetrics(f);
|
||||
|
||||
// Here we use the font width cache instead of
|
||||
// textwidth = fontMetrics().width(str);
|
||||
@ -390,7 +393,32 @@ int GuiPainter::text(int x, int y, docstring const & s,
|
||||
setQPainterPen(computeColor(f.realColor()));
|
||||
if (font() != ff)
|
||||
setFont(ff);
|
||||
|
||||
/* In LyX, the character direction is forced by the language.
|
||||
* Therefore, we have to signal that fact to Qt.
|
||||
*/
|
||||
#ifdef USE_RTL_OVERRIDE
|
||||
/* 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;
|
||||
drawText(x, y, str);
|
||||
#else
|
||||
/* This is a cleanr solution, but it has two drawbacks
|
||||
* - it seems that it does not work under Mac OS X
|
||||
* - it is not really documented
|
||||
*/
|
||||
//This is much stronger than setLayoutDirection.
|
||||
int flag = rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
|
||||
drawText(x + (rtl ? textwidth : 0), y - fm.maxAscent(), 0, 0,
|
||||
flag | Qt::TextDontClip,
|
||||
str);
|
||||
#endif
|
||||
//LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8())
|
||||
// << " at " << x << "," << y);
|
||||
return textwidth;
|
||||
@ -399,8 +427,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
|
||||
|
||||
int GuiPainter::text(int x, int y, docstring const & str, Font const & f)
|
||||
{
|
||||
docstring const dstr = directedString(str, f.isVisibleRightToLeft());
|
||||
return text(x, y, dstr, f.fontInfo());
|
||||
return text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft());
|
||||
}
|
||||
|
||||
|
||||
@ -410,7 +437,6 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
|
||||
GuiFontMetrics const & fm = getFontMetrics(f.fontInfo());
|
||||
FontInfo fi = f.fontInfo();
|
||||
bool const rtl = f.isVisibleRightToLeft();
|
||||
docstring const dstr = directedString(str, rtl);
|
||||
|
||||
// dimensions
|
||||
int const ascent = fm.maxAscent();
|
||||
@ -424,15 +450,15 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
|
||||
Color const orig = fi.realColor();
|
||||
fi.setPaintColor(other);
|
||||
setClipRect(QRect(x + xmin, y - ascent, xmax - xmin, height));
|
||||
int const textwidth = text(x, y, dstr, fi);
|
||||
int const textwidth = text(x, y, str, fi, rtl);
|
||||
|
||||
// Then the part in normal color
|
||||
// Note that in Qt5, it is not possible to use Qt::UniteClip
|
||||
fi.setPaintColor(orig);
|
||||
setClipRect(QRect(x, y - ascent, xmin, height));
|
||||
text(x, y, dstr, fi);
|
||||
text(x, y, str, fi, rtl);
|
||||
setClipRect(QRect(x + xmax, y - ascent, textwidth - xmax, height));
|
||||
text(x, y, dstr, fi);
|
||||
text(x, y, str, fi, rtl);
|
||||
setClipping(false);
|
||||
|
||||
return textwidth;
|
||||
|
@ -87,10 +87,10 @@ public:
|
||||
lyx::graphics::Image const & image);
|
||||
|
||||
/** draw a string at position x, y (y is the baseline). The
|
||||
* text direction is deduced from \c str.
|
||||
* text direction is given by \c rtl.
|
||||
* \return the width of the drawn text.
|
||||
*/
|
||||
virtual int text(int x, int y, docstring const & str, FontInfo const & f);
|
||||
virtual int text(int x, int y, docstring const & str, FontInfo const & f, bool rtl = false);
|
||||
|
||||
/** draw a string at position x, y (y is the baseline). The
|
||||
* text direction is enforced by the \c Font.
|
||||
|
@ -1502,23 +1502,5 @@ docstring bformat(docstring const & fmt,
|
||||
return subst(str, from_ascii("%%"), from_ascii("%"));
|
||||
}
|
||||
|
||||
|
||||
docstring directedString(docstring const & s, bool const rtl)
|
||||
{
|
||||
/* In LyX, the character direction is forced by the language.
|
||||
* Therefore, we have to signal that fact to Qt.
|
||||
* Source: http://www.iamcal.com/understanding-bidirectional-text/
|
||||
*/
|
||||
// Left-to-right override: forces to draw text left-to-right
|
||||
char_type const LRO = 0x202D;
|
||||
// Right-to-left override: forces to draw text right-to-left
|
||||
char_type const RLO = 0x202E;
|
||||
// Pop directional formatting: return to previous state
|
||||
char_type const PDF = 0x202C;
|
||||
return (rtl ? RLO : LRO) + s + PDF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
||||
|
@ -327,9 +327,6 @@ template<> docstring bformat(docstring const & fmt, int arg1, int arg2);
|
||||
template<> docstring bformat(docstring const & fmt, docstring arg1, docstring arg2, docstring arg3);
|
||||
template<> docstring bformat(docstring const & fmt, docstring arg1, docstring arg2, docstring arg3, docstring arg4);
|
||||
|
||||
/// Return a string with Unicode overrides to enforce the writing direction
|
||||
docstring directedString(docstring const & s, bool rtl);
|
||||
|
||||
|
||||
} // namespace support
|
||||
} // namespace lyx
|
||||
|
Loading…
Reference in New Issue
Block a user