* Full author contact details are available in file CREDITS.
*/
-#ifdef Q_OS_MAC
-#define USE_RTL_OVERRIDE 1
-#endif
-
#include <config.h>
#include "GuiPainter.h"
namespace lyx {
namespace frontend {
-
-const float Painter::thin_line = 0.0;
+
+const int Painter::thin_line = 0;
GuiPainter::GuiPainter(QPaintDevice * device, double pixel_ratio)
: QPainter(device), Painter(pixel_ratio),
void GuiPainter::setQPainterPen(QColor const & col,
- Painter::line_style ls, float lw)
+ Painter::line_style ls, int lw)
{
if (col == current_color_ && ls == current_ls_ && lw == current_lw_)
return;
case line_onoffdash: pen.setStyle(Qt::DotLine); break;
}
- pen.setWidthF(lw);
+ pen.setWidth(lw);
setPen(pen);
}
void GuiPainter::line(int x1, int y1, int x2, int y2,
Color col,
line_style ls,
- float lw)
+ int lw)
{
if (!isDrawingEnabled())
return;
Color col,
fill_style fs,
line_style ls,
- float lw)
+ int lw)
{
if (!isDrawingEnabled())
return;
void GuiPainter::rectangle(int x, int y, int w, int h,
Color col,
line_style ls,
- float lw)
+ int lw)
{
if (!isDrawingEnabled())
return;
}
+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)
+ FontInfo const & f, bool const rtl,
+ double const wordspacing)
{
//LYXERR0("text: x=" << x << ", s=" << s);
if (s.empty())
str = ' ' + str;
#endif
- QFont const & ff = getFont(f);
+ QFont ff = getFont(f);
+ ff.setWordSpacing(wordspacing);
GuiFontMetrics const & fm = getFontMetrics(f);
// 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;
textDecoration(f, x, y, textwidth);
- // Qt4 does not display a glyph whose codepoint is the
- // same as that of a soft-hyphen (0x00ad), unless it
- // occurs at a line-break. As a kludge, we force Qt to
- // render this glyph using a one-column line.
- // This is needed for some math glyphs.
- // Should the soft hyphen char be displayed at all?
- // I don't think so (i.e., Qt is correct as far as
- // texted is concerned). /spitz
- if (s.size() == 1 && str[0].unicode() == 0x00ad) {
- setQPainterPen(computeColor(f.realColor()));
- QTextLayout adsymbol(str);
- adsymbol.setFont(ff);
- adsymbol.beginLayout();
- QTextLine line = adsymbol.createLine();
- line.setNumColumns(1);
- line.setPosition(QPointF(0, -line.ascent()));
- adsymbol.endLayout();
- line.draw(this, QPointF(x, y));
- return textwidth;
- }
-
if (use_pixmap_cache_) {
QPixmap pm;
QString key = generateStringSignature(str, f);
// 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)) {
int const mD = fm.maxDescent();
int const h = mA + mD;
if (w > 0 && h > 0) {
- pm = QPixmap(pixelRatio() * w , pixelRatio() * h);
+ pm = QPixmap(static_cast<int>(pixelRatio() * w),
+ static_cast<int>(pixelRatio() * h));
#if QT_VERSION >= 0x050000
pm.setDevicePixelRatio(pixelRatio());
#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
// Draw the new cached pixmap.
drawPixmap(x + lb, y - mA, pm);
-
- return textwidth;
+ //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.
- */
-#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
+ do_drawText(x, y, str, rtl, f, ff);
//LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8())
// << " at " << x << "," << y);
return textwidth;
}
-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)
{
- return text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft());
+ return text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft(), wordspacing);
}
int GuiPainter::text(int x, int y, docstring const & str, Font const & f,
- Color other, size_type from, size_type to)
+ Color other, size_type const from, size_type const to,
+ double const wordspacing)
{
GuiFontMetrics const & fm = getFontMetrics(f.fontInfo());
FontInfo fi = f.fontInfo();
// dimensions
int const ascent = fm.maxAscent();
int const height = fm.maxAscent() + fm.maxDescent();
- int xmin = fm.pos2x(str, from, rtl);
- int xmax = fm.pos2x(str, to, rtl);
+ int xmin = fm.pos2x(str, from, rtl, wordspacing);
+ int xmax = fm.pos2x(str, to, rtl, wordspacing);
if (xmin > xmax)
swap(xmin, xmax);
fi.setPaintColor(other);
QRegion const clip(x + xmin, y - ascent, xmax - xmin, height);
setClipRegion(clip);
- int const textwidth = text(x, y, str, fi, rtl);
+ int const textwidth = text(x, y, str, fi, rtl, wordspacing);
// Then the part in normal color
// Note that in Qt5, it is not possible to use Qt::UniteClip,
fi.setPaintColor(orig);
QRegion region(viewport());
setClipRegion(region - clip);
- text(x, y, str, fi, rtl);
+ text(x, y, str, fi, rtl, wordspacing);
setClipping(false);
return textwidth;
}
-void GuiPainter::doubleUnderline(FontInfo const & f, int x, int y, int width)
+void GuiPainter::underline(FontInfo const & f, int x, int y, int width,
+ line_style ls)
{
FontMetrics const & fm = theFontMetrics(f);
+ int const pos = fm.underlinePos();
- int const below = max(fm.maxDescent() / 2, 2);
-
- line(x, y + below, x + width, y + below, f.realColor());
- line(x, y + below - 2, x + width, y + below - 2, f.realColor());
+ line(x, y + pos, x + width, y + pos,
+ f.realColor(), ls, fm.lineWidth());
}
-void GuiPainter::underline(FontInfo const & f, int x, int y, int width)
+void GuiPainter::strikeoutLine(FontInfo const & f, int x, int y, int width)
{
FontMetrics const & fm = theFontMetrics(f);
+ int const pos = fm.strikeoutPos();
- int const below = max(fm.maxDescent() / 2, 2);
- int const height = max((fm.maxDescent() / 4) - 1, 1);
-
- if (height < 2)
- line(x, y + below, x + width, y + below, f.realColor());
- else
- fillRectangle(x, y + below, width, below + height, f.realColor());
+ line(x, y - pos, x + width, y - pos,
+ f.realColor(), line_solid, fm.lineWidth());
}
-void GuiPainter::strikeoutLine(FontInfo const & f, int x, int y, int width)
+void GuiPainter::doubleUnderline(FontInfo const & f, int x, int y, int width)
{
FontMetrics const & fm = theFontMetrics(f);
+ int const pos1 = fm.underlinePos() + fm.lineWidth();
+ int const pos2 = fm.underlinePos() - fm.lineWidth() + 1;
- int const middle = max((fm.maxHeight() / 4), 1);
- int const height = middle/3;
-
- if (height < 2)
- line(x, y - middle, x + width, y - middle, f.realColor());
- else
- fillRectangle(x, y - middle, width, height, f.realColor());
+ line(x, y + pos1, x + width, y + pos1,
+ f.realColor(), line_solid, fm.lineWidth());
+ line(x, y + pos2, x + width, y + pos2,
+ f.realColor(), line_solid, fm.lineWidth());
}