Details
-
Bug
-
Resolution: Out of scope
-
P2: Important
-
4.4.0
-
None
Description
When painting text to a curve, the individual characters seem wobbly... The characters are slightly rotated or positioned improperly. The glitch is quite subtle.
Update: rescheduled to some future release. This is a problem we've had for a long time in Qt and it's due to the way our font engines work.
It can be solved by using the painter path fallback when a complex transformation is set. For example instead of:
p.drawText( 0,0, character );
use
QPainterPath glyphPath;
glyphPath.addText(0, 0, p.font(), character);
p.fillPath(glyphPath, p.pen().color());
though we do not want to do this in the default case as it will be a lot slower. The idea instead is to maybe add a render hint that specifies that you want high quality text transformation.
Test case main.cpp to reproduce
================================
#include <QtGui>
#define PI 3.14159265358979323846264338327f
class Widget : public QWidget
{
public:
Widget(QWidget *parent=0);
void paintEvent(QPaintEvent *);
};
Widget::Widget(QWidget *parent) : QWidget(parent)
{
}
void Widget::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.fillRect( rect(), QColor(255, 252, 245) );
//---------------------
QFont font("Verdana");
font.setPixelSize(24);
QFontMetricsF fontMetrics(font);
QRect r = rect();
int textRadius = qMax( 50, (int) (qMin(r.width(), r.height())/2 - fontMetrics.height()) );
p.translate( r.center() );
//---------------------
QString text = "[ The Brown Fox Jumped Over The Log ]";
// append an underline to the text, so that we can see
// the quality of baseline for characters on this path
for(int i=0; i<100; i++) text.append("_ ");
text.append( "]");
p.setFont(font);
qreal textWidth = fontMetrics.width(text);
QRectF textRect( -textRadius, -textRadius, 2*textRadius, 2*textRadius );
float textSweepAngle = (360.0f * textWidth) / (2*PI*textRadius);
QPainterPath textPath;
textPath.arcMoveTo( textRect, 0 );
textPath.arcTo ( textRect, 0, -textSweepAngle );
//---------------------
//paint baseline
p.setRenderHint( QPainter::Antialiasing, true );
p.strokePath( textPath, QPen(Qt::red) );
p.setRenderHint( QPainter::Antialiasing, false );
//---------------------
//paint string
p.setPen( Qt::blue );
qreal builtWidth = 0;
for(int i=0; i<text.length(); i++)
{
QString character( text[i] );
qreal characterWidth = fontMetrics.width(character);
qreal percent = builtWidth / textWidth;
qreal angle = textPath.angleAtPercent(percent);
QPointF point = textPath.pointAtPercent(percent);
if( angle == 0 )
p.drawText( point, character );
else
builtWidth = fontMetrics.width( text.left(i+1));
}
}
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Widget w; w.show();
return app.exec();
}