Allow automatic text direction in Painter::text()

It is wrong to assume that direction is left-to-right when no indication exist.

Add a new enum with values LtR, RtL and Auto to be used as argument of
the private text() methods. When direction is Auto, let Qt decide how
the string shall be layed out.

This is reimplementation of 51ee267c. A direct cherry-pick was not possible.

Fixes bug #10169.
This commit is contained in:
Jean-Marc Lasgouttes 2016-05-31 14:49:13 +02:00
parent a762244ca6
commit 7855c0c1fc
4 changed files with 46 additions and 29 deletions

View File

@ -133,15 +133,14 @@ public:
virtual void image(int x, int y, int w, int h, virtual void image(int x, int y, int w, int h,
graphics::Image const & image) = 0; graphics::Image const & image) = 0;
/** draw a string at position x, y (y is the baseline). The /** draw a string at position x, y (y is the baseline). The text
* text direction is given by \c rtl. * direction depends on the string itself.
* \return the width of the drawn text. * \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) = 0;
bool rtl = false, double wordspacing = 0.0) = 0;
/** draw a string at position x, y (y is the baseline). The /** draw a string at position x, y (y is the baseline). The text
* text direction is enforced by the \c Font. * direction is enforced by the \c Font.
* \return the width of the drawn text. * \return the width of the drawn text.
*/ */
virtual int text(int x, int y, docstring const & str, Font const & f, virtual int text(int x, int y, docstring const & str, Font const & f,

View File

@ -333,7 +333,14 @@ int GuiPainter::text(int x, int y, char_type c, FontInfo const & f)
} }
void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const & f, QFont ff) int GuiPainter::text(int x, int y, docstring const & s, FontInfo const & f)
{
return text(x, y, s, f, Auto, 0.0);
}
void GuiPainter::do_drawText(int x, int y, QString str, Direction const dir,
FontInfo const & f, QFont ff)
{ {
setQPainterPen(computeColor(f.realColor())); setQPainterPen(computeColor(f.realColor()));
if (font() != ff) if (font() != ff)
@ -346,10 +353,10 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
/* Use unicode override characters to enforce drawing direction /* Use unicode override characters to enforce drawing direction
* Source: http://www.iamcal.com/understanding-bidirectional-text/ * Source: http://www.iamcal.com/understanding-bidirectional-text/
*/ */
if (rtl) if (dir == RtL)
// Right-to-left override: forces to draw text right-to-left // Right-to-left override: forces to draw text right-to-left
str = QChar(0x202E) + str; str = QChar(0x202E) + str;
else else if (dir == LtR)
// Left-to-right override: forces to draw text left-to-right // Left-to-right override: forces to draw text left-to-right
str = QChar(0x202D) + str; str = QChar(0x202D) + str;
drawText(x, y, str); drawText(x, y, str);
@ -360,8 +367,12 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
* Keep it here for now, in case it can be helpful * Keep it here for now, in case it can be helpful
*/ */
//This is much stronger than setLayoutDirection. //This is much stronger than setLayoutDirection.
int flag = rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight; int flag = 0;
drawText(x + (rtl ? textwidth : 0), y - fm.maxAscent(), 0, 0, if (dir == RtL)
flag = Qt::TextForceRightToLeft;
else if (dir == LtR)
flag = Qt::TextForceLeftToRight;
drawText(x + ((dir == RtL) ? textwidth : 0), y - fm.maxAscent(), 0, 0,
flag | Qt::TextDontClip, flag | Qt::TextDontClip,
str); str);
#endif #endif
@ -369,7 +380,7 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
int GuiPainter::text(int x, int y, docstring const & s, int GuiPainter::text(int x, int y, docstring const & s,
FontInfo const & f, bool const rtl, FontInfo const & f, Direction const dir,
double const wordspacing) double const wordspacing)
{ {
//LYXERR0("text: x=" << x << ", s=" << s); //LYXERR0("text: x=" << x << ", s=" << s);
@ -421,7 +432,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
// Only the left bearing of the first character is important // Only the left bearing of the first character is important
// as we always write from left to right, even for // as we always write from left to right, even for
// right-to-left languages. // right-to-left languages.
// FIXME: this is probably broken for RTL now that we draw full strings. // FIXME: this is probably broken for RtL now that we draw full strings.
// Morover the first/last element is possibly not the right one since the glyph may have changed. // Morover the first/last element is possibly not the right one since the glyph may have changed.
int const lb = min(fm.lbearing(s[0]), 0); int const lb = min(fm.lbearing(s[0]), 0);
int const mA = fm.maxAscent(); int const mA = fm.maxAscent();
@ -446,7 +457,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
#endif #endif
pm.fill(Qt::transparent); pm.fill(Qt::transparent);
GuiPainter p(&pm, pixelRatio()); GuiPainter p(&pm, pixelRatio());
p.do_drawText(-lb, mA, str, rtl, f, ff); p.do_drawText(-lb, mA, str, dir, f, ff);
QPixmapCache::insert(key, pm); QPixmapCache::insert(key, pm);
//LYXERR(Debug::PAINTING, "h=" << h << " mA=" << mA << " mD=" << mD //LYXERR(Debug::PAINTING, "h=" << h << " mA=" << mA << " mD=" << mD
// << " w=" << w << " lb=" << lb << " tw=" << textwidth // << " w=" << w << " lb=" << lb << " tw=" << textwidth
@ -460,7 +471,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
} }
// don't use the pixmap cache, // don't use the pixmap cache,
do_drawText(x, y, str, rtl, f, ff); do_drawText(x, y, str, dir, f, ff);
//LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8()) //LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8())
// << " at " << x << "," << y); // << " at " << x << "," << y);
return textwidth; return textwidth;
@ -470,7 +481,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
int GuiPainter::text(int x, int y, docstring const & str, Font const & f, int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
double const wordspacing) double const wordspacing)
{ {
return text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft(), wordspacing); return text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft() ? RtL : LtR, wordspacing);
} }
@ -480,13 +491,13 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
{ {
GuiFontMetrics const & fm = getFontMetrics(f.fontInfo()); GuiFontMetrics const & fm = getFontMetrics(f.fontInfo());
FontInfo fi = f.fontInfo(); FontInfo fi = f.fontInfo();
bool const rtl = f.isVisibleRightToLeft(); Direction const dir = f.isVisibleRightToLeft() ? RtL : LtR;
// dimensions // dimensions
int const ascent = fm.maxAscent(); int const ascent = fm.maxAscent();
int const height = fm.maxAscent() + fm.maxDescent(); int const height = fm.maxAscent() + fm.maxDescent();
int xmin = fm.pos2x(str, from, rtl, wordspacing); int xmin = fm.pos2x(str, from, dir == RtL, wordspacing);
int xmax = fm.pos2x(str, to, rtl, wordspacing); int xmax = fm.pos2x(str, to, dir == RtL, wordspacing);
if (xmin > xmax) if (xmin > xmax)
swap(xmin, xmax); swap(xmin, xmax);
@ -495,7 +506,7 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
fi.setPaintColor(other); fi.setPaintColor(other);
QRegion const clip(x + xmin, y - ascent, xmax - xmin, height); QRegion const clip(x + xmin, y - ascent, xmax - xmin, height);
setClipRegion(clip); setClipRegion(clip);
int const textwidth = text(x, y, str, fi, rtl, wordspacing); int const textwidth = text(x, y, str, fi, dir, wordspacing);
// Then the part in normal color // Then the part in normal color
// Note that in Qt5, it is not possible to use Qt::UniteClip, // Note that in Qt5, it is not possible to use Qt::UniteClip,
@ -503,7 +514,7 @@ int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
fi.setPaintColor(orig); fi.setPaintColor(orig);
QRegion region(viewport()); QRegion region(viewport());
setClipRegion(region - clip); setClipRegion(region - clip);
text(x, y, str, fi, rtl, wordspacing); text(x, y, str, fi, dir, wordspacing);
setClipping(false); setClipping(false);
return textwidth; return textwidth;

View File

@ -105,15 +105,14 @@ public:
virtual void image(int x, int y, int w, int h, virtual void image(int x, int y, int w, int h,
lyx::graphics::Image const & image); lyx::graphics::Image const & image);
/** draw a string at position x, y (y is the baseline). The /** draw a string at position x, y (y is the baseline). The text
* text direction is given by \c rtl. * direction depends on the string itself.
* \return the width of the drawn text. * \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, double wordspacing = 0.0);
/** draw a string at position x, y (y is the baseline). The /** draw a string at position x, y (y is the baseline). The text
* text direction is enforced by the \c Font. * direction is enforced by the \c Font.
* \return the width of the drawn text. * \return the width of the drawn text.
*/ */
virtual int text(int x, int y, docstring const & str, Font const & f, virtual int text(int x, int y, docstring const & str, Font const & f,
@ -186,8 +185,14 @@ private:
void setQPainterPen(QColor const & col, void setQPainterPen(QColor const & col,
line_style ls = line_solid, int lw = thin_line); line_style ls = line_solid, int lw = thin_line);
// Helper for text() method /// Direction for painting text
void do_drawText(int x, int y, QString str, bool rtl, FontInfo const & f, QFont ff); enum Direction { LtR, RtL, Auto };
/// Helpers for text() method
void do_drawText(int x, int y, QString str, Direction dir, FontInfo const & f, QFont ff);
///
virtual int text(int x, int y, docstring const & str, FontInfo const & f,
Direction dir, double wordspacing);
QColor current_color_; QColor current_color_;
Painter::line_style current_ls_; Painter::line_style current_ls_;

View File

@ -45,6 +45,8 @@ What's new
* USER INTERFACE * USER INTERFACE
- Fix display of labels in right-to-left languages (bug 10169).
- When a counter is stepped, reset recursively all subcounters (bug #10063). - When a counter is stepped, reset recursively all subcounters (bug #10063).
- Fix on screen narrow box when using \width as box width unit (bug 10048). - Fix on screen narrow box when using \width as box width unit (bug 10048).