]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiPainter.cpp
Merge branch 'master' into biblatex2
[lyx.git] / src / frontends / qt4 / GuiPainter.cpp
index 12d4f72eb98e04b0b040ff8381bbff1502a0403b..448b5a44b23f6231b6672feb8144a48cb08dd43e 100644 (file)
@@ -29,6 +29,8 @@
 #include "support/lassert.h"
 #include "support/debug.h"
 
+#include <algorithm>
+
 #include <QPixmapCache>
 #include <QTextLayout>
 
@@ -80,8 +82,11 @@ void GuiPainter::setQPainterPen(QColor const & col,
        pen.setColor(col);
 
        switch (ls) {
-               case line_solid: pen.setStyle(Qt::SolidLine); break;
-               case line_onoffdash: pen.setStyle(Qt::DotLine); break;
+       case line_solid:
+       case line_solid_aliased:
+               pen.setStyle(Qt::SolidLine); break;
+       case line_onoffdash:
+               pen.setStyle(Qt::DotLine); break;
        }
 
        pen.setWidth(lw);
@@ -186,7 +191,7 @@ void GuiPainter::line(int x1, int y1, int x2, int y2,
 
        setQPainterPen(computeColor(col), ls, lw);
        bool const do_antialiasing = renderHints() & TextAntialiasing
-               && x1 != x2 && y1 != y2;
+               && x1 != x2 && y1 != y2 && ls != line_solid_aliased;
        setRenderHint(Antialiasing, do_antialiasing);
        drawLine(x1, y1, x2, y2);
        setRenderHint(Antialiasing, false);
@@ -208,6 +213,8 @@ void GuiPainter::lines(int const * xp, int const * yp, int np,
        if (np > points.size())
                points.resize(2 * np);
 
+       // Note: the proper way to not get blurry vertical and horizontal lines is
+       // to add 0.5 to all coordinates.
        bool antialias = false;
        for (int i = 0; i < np; ++i) {
                points[i].setX(xp[i]);
@@ -218,7 +225,8 @@ void GuiPainter::lines(int const * xp, int const * yp, int np,
        QColor const color = computeColor(col);
        setQPainterPen(color, ls, lw);
        bool const text_is_antialiased = renderHints() & TextAntialiasing;
-       setRenderHint(Antialiasing, antialias && text_is_antialiased);
+       setRenderHint(Antialiasing,
+                     antialias && text_is_antialiased && ls != line_solid_aliased);
        if (fs == fill_none) {
                drawPolyline(points.data(), np);
        } else {
@@ -259,7 +267,7 @@ void GuiPainter::path(int const * xp, int const * yp,
        QColor const color = computeColor(col);
        setQPainterPen(color, ls, lw);
        bool const text_is_antialiased = renderHints() & TextAntialiasing;
-       setRenderHint(Antialiasing, text_is_antialiased);
+       setRenderHint(Antialiasing, text_is_antialiased && ls != line_solid_aliased);
        drawPath(bpath);
        if (fs != fill_none)
                fillPath(bpath, QBrush(color));
@@ -333,7 +341,15 @@ void 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)
+void GuiPainter::text(int x, int y, docstring const & s, FontInfo const & f)
+{
+       text(x, y, s, f, Auto, 0.0, 0.0);
+}
+
+
+void GuiPainter::do_drawText(int x, int y, QString str,
+                             GuiPainter::Direction const dir,
+                             FontInfo const & f, QFont ff)
 {
        setQPainterPen(computeColor(f.realColor()));
        if (font() != ff)
@@ -346,10 +362,10 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
        /* Use unicode override characters to enforce drawing direction
         * Source: http://www.iamcal.com/understanding-bidirectional-text/
         */
-       if (rtl)
+       if (dir == RtL)
                // Right-to-left override: forces to draw text right-to-left
                str = QChar(0x202E) + str;
-       else
+       else if (dir == LtR)
                // Left-to-right override: forces to draw text left-to-right
                str =  QChar(0x202D) + str;
        drawText(x, y, str);
@@ -360,8 +376,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
         */
        //This is much stronger than setLayoutDirection.
-       int flag = rtl ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
-       drawText(x + (rtl ? textwidth : 0), y - fm.maxAscent(), 0, 0,
+       int flag = 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,
                 str);
 #endif
@@ -369,8 +389,8 @@ void GuiPainter::do_drawText(int x, int y, QString str, bool rtl, FontInfo const
 
 
 void GuiPainter::text(int x, int y, docstring const & s,
-                      FontInfo const & f, bool const rtl,
-                      double const wordspacing)
+                      FontInfo const & f, Direction const dir,
+                      double const wordspacing, double const tw)
 {
        //LYXERR0("text: x=" << x << ", s=" << s);
        if (s.empty() || !isDrawingEnabled())
@@ -382,8 +402,8 @@ void GuiPainter::text(int x, int y, docstring const & s,
        of the symbol in the font (as given in lib/symbols) as a char_type to the
        frontend. This is just wrong, because the symbol is no UCS4 character at
        all. You can think of this number as the code point of the symbol in a
-       custom symbol encoding. It works because this char_type is lateron again
-       interpreted as a position in the font again.
+       custom symbol encoding. It works because this char_type is later on again
+       interpreted as a position in the font.
        The correct solution would be to have extra functions for symbols, but that
        would require to duplicate a lot of frontend and mathed support code.
        */
@@ -400,11 +420,13 @@ void GuiPainter::text(int x, int y, docstring const & s,
        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
-       // Note that we have to take in account space stretching (word spacing)
-       int const textwidth = fm.width(s) + count(s.begin(), s.end(), ' ') * wordspacing;
+       int textwidth = 0;
+       if (tw == 0.0)
+               // Note that we have to take in account space stretching (word spacing)
+               textwidth = fm.width(s) +
+                       static_cast<int>(fm.countExpanders(s) * wordspacing);
+       else
+               textwidth = static_cast<int>(tw);
 
        textDecoration(f, x, y, textwidth);
 
@@ -443,7 +465,7 @@ void GuiPainter::text(int x, int y, docstring const & s,
 #endif
                        pm.fill(Qt::transparent);
                        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);
                        //LYXERR(Debug::PAINTING, "h=" << h << "  mA=" << mA << "  mD=" << mD
                        //      << "  w=" << w << "  lb=" << lb << "  tw=" << textwidth
@@ -456,33 +478,43 @@ void GuiPainter::text(int x, int y, docstring const & s,
                return;
        }
 
-       // don't use the pixmap cache,
-       do_drawText(x, y, str, rtl, f, ff);
+       // don't use the pixmap cache
+       setQPainterPen(computeColor(f.realColor()));
+       if (dir != Auto) {
+               QTextLayout const * ptl = fm.getTextLayout(s, dir == RtL, wordspacing);
+               ptl->draw(this, QPointF(x, y - fm.maxAscent()));
+       }
+       else {
+               if (font() != ff)
+                       setFont(ff);
+               drawText(x, y, str);
+       }
        //LYXERR(Debug::PAINTING, "draw " << string(str.toUtf8())
        //      << " at " << x << "," << y);
 }
 
 
 void GuiPainter::text(int x, int y, docstring const & str, Font const & f,
-                      double const wordspacing)
+                      double const wordspacing, double const tw)
 {
-       text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft(), wordspacing);
+       text(x, y, str, f.fontInfo(), f.isVisibleRightToLeft() ? RtL : LtR,
+            wordspacing, tw);
 }
 
 
 void GuiPainter::text(int x, int y, docstring const & str, Font const & f,
                       Color other, size_type const from, size_type const to,
-                      double const wordspacing)
+                      double const wordspacing, double const tw)
 {
        GuiFontMetrics const & fm = getFontMetrics(f.fontInfo());
        FontInfo fi = f.fontInfo();
-       bool const rtl = f.isVisibleRightToLeft();
+       Direction const dir = f.isVisibleRightToLeft() ? RtL : LtR;
 
        // dimensions
        int const ascent = fm.maxAscent();
        int const height = fm.maxAscent() + fm.maxDescent();
-       int xmin = fm.pos2x(str, from, rtl, wordspacing);
-       int xmax = fm.pos2x(str, to, rtl, wordspacing);
+       int xmin = fm.pos2x(str, from, dir == RtL, wordspacing);
+       int xmax = fm.pos2x(str, to, dir == RtL, wordspacing);
        if (xmin > xmax)
                swap(xmin, xmax);
 
@@ -491,7 +523,7 @@ void GuiPainter::text(int x, int y, docstring const & str, Font const & f,
        fi.setPaintColor(other);
        QRegion const clip(x + xmin, y - ascent, xmax - xmin, height);
        setClipRegion(clip);
-       text(x, y, str, fi, rtl, wordspacing);
+       text(x, y, str, fi, dir, wordspacing, tw);
 
        // Then the part in normal color
        // Note that in Qt5, it is not possible to use Qt::UniteClip,
@@ -499,7 +531,7 @@ void GuiPainter::text(int x, int y, docstring const & str, Font const & f,
        fi.setPaintColor(orig);
        QRegion region(viewport());
        setClipRegion(region - clip);
-       text(x, y, str, fi, rtl, wordspacing);
+       text(x, y, str, fi, dir, wordspacing, tw);
        setClipping(false);
 }