Fix drawing with pixmap cache

The culprit was that the computation of textwidth did not take wordspacing in account.

Also fictor the code so that the pixmap path can use the special RTL handling.

It is not clear however that the handling of left and right bearing works correctly.
This commit is contained in:
Jean-Marc Lasgouttes 2015-10-19 16:34:04 +02:00
parent 26eb5092fb
commit 1e075bdf55
2 changed files with 45 additions and 38 deletions

View File

@ -289,6 +289,41 @@ 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)
{
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.
*/
#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;
drawText(x, y, str);
#else
/* This looks like a cleaner solution, but it has drawbacks
* - does not work reliably (Mac OS X, ...)
* - it is not really documented
* Keep it here for now, in case it can be helpful
*/
//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
}
int GuiPainter::text(int x, int y, docstring const & s,
FontInfo const & f, bool const rtl,
double const wordspacing)
@ -324,7 +359,8 @@ int GuiPainter::text(int x, int y, docstring const & s,
// Here we use the font width cache instead of
// textwidth = fontMetrics().width(str);
// because the above is awfully expensive on MacOSX
int const textwidth = fm.width(s);
// Note that we have to take in account space stretching (word spacing)
int const textwidth = fm.width(s) + count(s.begin(), s.end(), ' ') * wordspacing;
if (!isDrawingEnabled())
return textwidth;
@ -341,6 +377,8 @@ int GuiPainter::text(int x, int y, docstring const & s,
// Only the left bearing of the first character is important
// as we always write from left to right, even for
// right-to-left languages.
// 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.
int const lb = min(fm.lbearing(s[0]), 0);
int const mA = fm.maxAscent();
if (QPixmapCache::find(key, pm)) {
@ -364,12 +402,7 @@ int GuiPainter::text(int x, int y, docstring const & s,
#endif
pm.fill(Qt::transparent);
GuiPainter p(&pm, pixelRatio());
p.setQPainterPen(computeColor(f.realColor()));
if (p.font() != ff)
p.setFont(ff);
// We need to draw the text as LTR as we use our own bidi code.
p.setLayoutDirection(Qt::LeftToRight);
p.drawText(-lb, mA, str);
p.do_drawText(-lb, mA, str, rtl, f, ff);
QPixmapCache::insert(key, pm);
//LYXERR(Debug::PAINTING, "h=" << h << " mA=" << mA << " mD=" << mD
// << " w=" << w << " lb=" << lb << " tw=" << textwidth
@ -377,42 +410,13 @@ int GuiPainter::text(int x, int y, docstring const & s,
// Draw the new cached pixmap.
drawPixmap(x + lb, y - mA, pm);
//rectangle(x-lb, y-mA, w, h, Color_green);
}
return textwidth;
}
// don't use the pixmap cache,
// draw directly onto the painting device
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.
*/
#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;
drawText(x, y, str);
#else
/* This looks like a cleaner solution, but it has drawbacks
* - does not work reliably (Mac OS X, ...)
* - it is not really documented
* Keep it here for now, in case it can be helpful
*/
//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
do_drawText(x, y, str, rtl, f, ff);
//LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8())
// << " at " << x << "," << y);
return textwidth;

View File

@ -168,6 +168,9 @@ private:
void setQPainterPen(QColor const & col,
line_style ls = line_solid, int lw = thin_line);
// Helper for text() method
void do_drawText(int x, int y, QString str, bool rtl, FontInfo const & f, QFont ff);
QColor current_color_;
Painter::line_style current_ls_;
int current_lw_;