src/gui/painting/qpainter.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
--- a/src/gui/painting/qpainter.cpp	Fri Sep 17 08:34:18 2010 +0300
+++ b/src/gui/painting/qpainter.cpp	Mon Oct 04 01:19:32 2010 +0300
@@ -90,6 +90,15 @@
                     const QRectF &_r, int tf, const QTextOption *option, const QString& str, QRectF *brect,
                     int tabstops, int* tabarray, int tabarraylen,
                     QPainter *painter);
+static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe,
+                                   QTextCharFormat::UnderlineStyle underlineStyle,
+                                   const QTextItem::RenderFlags flags, qreal width,
+                                   const QTextCharFormat &charFormat);
+// Helper function to calculate left most position, width and flags for decoration drawing
+static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray,
+                                    const QFixedPoint *positions, int glyphCount,
+                                    QFontEngine *fontEngine, const QFont &font,
+                                    const QTextCharFormat &charFormat);
 
 static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
 {
@@ -687,9 +696,9 @@
 
         skip = false;
 
-        QBrush penBrush = s->pen.brush();
-        Qt::BrushStyle brushStyle = s->brush.style();
-        Qt::BrushStyle penBrushStyle = penBrush.style();
+        QBrush penBrush = (qpen_style(s->pen) == Qt::NoPen) ? QBrush(Qt::NoBrush) : qpen_brush(s->pen);
+        Qt::BrushStyle brushStyle = qbrush_style(s->brush);
+        Qt::BrushStyle penBrushStyle = qbrush_style(penBrush);
         alpha = (penBrushStyle != Qt::NoBrush
                  && (penBrushStyle < Qt::LinearGradientPattern && penBrush.color().alpha() != 255)
                  && !penBrush.isOpaque())
@@ -5853,10 +5862,14 @@
         return;
     }
 
-    if (d->extended->type() == QPaintEngine::OpenGL2 && !staticText_d->untransformedCoordinates) {
+    bool paintEngineSupportsTransformations = d->extended->type() == QPaintEngine::OpenGL2
+                                           || d->extended->type() == QPaintEngine::OpenVG
+                                           || d->extended->type() == QPaintEngine::OpenGL;
+
+    if (paintEngineSupportsTransformations && !staticText_d->untransformedCoordinates) {
         staticText_d->untransformedCoordinates = true;
         staticText_d->needsRelayout = true;
-    } else if (d->extended->type() != QPaintEngine::OpenGL2 && staticText_d->untransformedCoordinates) {
+    } else if (!paintEngineSupportsTransformations && staticText_d->untransformedCoordinates) {
         staticText_d->untransformedCoordinates = false;
         staticText_d->needsRelayout = true;
     }
@@ -5895,7 +5908,7 @@
 
     // Recreate the layout of the static text because the matrix or font has changed
     if (staticTextNeedsReinit)
-        staticText_d->init();    
+        staticText_d->init();
 
     if (transformedPosition != staticText_d->position) { // Translate to actual position
         QFixed fx = QFixed::fromReal(transformedPosition.x());
@@ -5923,6 +5936,10 @@
             currentColor = item->color;
         }
         d->extended->drawStaticTextItem(item);
+
+        drawDecorationForGlyphs(this, item->glyphs, item->glyphPositions,
+                                item->numGlyphs, item->fontEngine, staticText_d->font,
+                                QTextCharFormat());
     }
     if (currentColor != oldPen.color())
         setPen(oldPen);
@@ -6290,14 +6307,14 @@
     return pixmap;
 }
 
-static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QTextItemInt &ti)
-{
-    QTextCharFormat::UnderlineStyle underlineStyle = ti.underlineStyle;
+static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const QFontEngine *fe,
+                                   QTextCharFormat::UnderlineStyle underlineStyle,
+                                   const QTextItem::RenderFlags flags, qreal width,
+                                   const QTextCharFormat &charFormat)
+{
     if (underlineStyle == QTextCharFormat::NoUnderline
-        && !(ti.flags & (QTextItem::StrikeOut | QTextItem::Overline)))
-        return;
-
-    QFontEngine *fe = ti.fontEngine;
+        && !(flags & (QTextItem::StrikeOut | QTextItem::Overline)))
+        return;
 
     const QPen oldPen = painter->pen();
     const QBrush oldBrush = painter->brush();
@@ -6307,7 +6324,7 @@
     pen.setWidthF(fe->lineThickness().toReal());
     pen.setCapStyle(Qt::FlatCap);
 
-    QLineF line(pos.x(), pos.y(), pos.x() + ti.width.toReal(), pos.y());
+    QLineF line(pos.x(), pos.y(), pos.x() + width, pos.y());
 
     const qreal underlineOffset = fe->underlinePosition().toReal();
     // deliberately ceil the offset to avoid the underline coming too close to
@@ -6322,21 +6339,21 @@
         painter->save();
         painter->translate(0, pos.y() + 1);
 
-        QColor uc = ti.charFormat.underlineColor();
+        QColor uc = charFormat.underlineColor();
         if (uc.isValid())
             pen.setColor(uc);
 
         // Adapt wave to underlineOffset or pen width, whatever is larger, to make it work on all platforms
         const QPixmap wave = generateWavyPixmap(qMax(underlineOffset, pen.widthF()), pen);
-        const int descent = (int) ti.descent.toReal();
+        const int descent = (int) fe->descent().toReal();
 
         painter->setBrushOrigin(painter->brushOrigin().x(), 0);
-        painter->fillRect(pos.x(), 0, qCeil(ti.width.toReal()), qMin(wave.height(), descent), wave);
+        painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
         painter->restore();
     } else if (underlineStyle != QTextCharFormat::NoUnderline) {
         QLineF underLine(line.x1(), underlinePos, line.x2(), underlinePos);
 
-        QColor uc = ti.charFormat.underlineColor();
+        QColor uc = charFormat.underlineColor();
         if (uc.isValid())
             pen.setColor(uc);
 
@@ -6348,14 +6365,14 @@
     pen.setStyle(Qt::SolidLine);
     pen.setColor(oldPen.color());
 
-    if (ti.flags & QTextItem::StrikeOut) {
+    if (flags & QTextItem::StrikeOut) {
         QLineF strikeOutLine = line;
         strikeOutLine.translate(0., - fe->ascent().toReal() / 3.);
         painter->setPen(pen);
         painter->drawLine(strikeOutLine);
     }
 
-    if (ti.flags & QTextItem::Overline) {
+    if (flags & QTextItem::Overline) {
         QLineF overLine = line;
         overLine.translate(0., - fe->ascent().toReal());
         painter->setPen(pen);
@@ -6366,6 +6383,50 @@
     painter->setBrush(oldBrush);
 }
 
+static void drawDecorationForGlyphs(QPainter *painter, const glyph_t *glyphArray,
+                                    const QFixedPoint *positions, int glyphCount,
+                                    QFontEngine *fontEngine, const QFont &font,
+                                    const QTextCharFormat &charFormat)
+{
+    if (!(font.underline() || font.strikeOut() || font.overline()))
+        return;
+
+    QFixed leftMost;
+    QFixed rightMost;
+    QFixed baseLine;
+    for (int i=0; i<glyphCount; ++i) {
+        glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
+        if (i == 0 || leftMost > positions[i].x)
+            leftMost = positions[i].x;
+
+        // We don't support glyphs that do not share a common baseline. If this turns out to
+        // be a relevant use case, then we need to find clusters of glyphs that share a baseline
+        // and do a drawTextItemDecorations call per cluster.
+        if (i == 0 || baseLine < positions[i].y)
+            baseLine = positions[i].y;
+
+        // We use the advance rather than the actual bounds to match the algorithm in drawText()
+        if (i == 0 || rightMost < positions[i].x + gm.xoff)
+            rightMost = positions[i].x + gm.xoff;
+    }
+
+    QFixed width = rightMost - leftMost;
+    QTextItem::RenderFlags flags = 0;
+
+    if (font.underline())
+        flags |= QTextItem::Underline;
+    if (font.overline())
+        flags |= QTextItem::Overline;
+    if (font.strikeOut())
+        flags |= QTextItem::StrikeOut;
+
+    drawTextItemDecoration(painter, QPointF(leftMost.toReal(), baseLine.toReal()),
+                           fontEngine,
+                           font.underline() ? QTextCharFormat::SingleUnderline
+                                            : QTextCharFormat::NoUnderline, flags,
+                           width.toReal(), charFormat);
+}
+
 void QPainter::drawTextItem(const QPointF &p, const QTextItem &_ti)
 {
 #ifdef QT_DEBUG_DRAW
@@ -6496,7 +6557,8 @@
         else
             d->engine->drawTextItem(p, ti);
     }
-    drawTextItemDecoration(this, p, ti);
+    drawTextItemDecoration(this, p, ti.fontEngine, ti.underlineStyle, ti.flags, ti.width.toReal(),
+                           ti.charFormat);
 
     if (d->state->renderHints != oldRenderHints) {
         d->state->renderHints = oldRenderHints;
@@ -8966,7 +9028,7 @@
 {
     Q_D(QPainter);
 
-    if (!d->engine)
+    if (!d->engine || pixmap.isNull())
         return;
 
 #ifndef QT_NO_DEBUG