Yet another text rendering improvement/optimization

This commit is contained in:
Martin Tůma 2019-10-03 22:39:05 +02:00
parent aacc42c25d
commit a58962ab93
4 changed files with 46 additions and 27 deletions

View File

@ -11,7 +11,7 @@ bool TextItem::collidesWithItem(const TextItem *other) const
return other->shape().intersects(shape()); return other->shape().intersects(shape());
} }
int TextItem::avgCharWidth() const qreal TextItem::avgCharWidth() const
{ {
qreal ratio; qreal ratio;
ushort cp = _text.at(0).unicode(); ushort cp = _text.at(0).unicode();
@ -21,12 +21,12 @@ int TextItem::avgCharWidth() const
ratio = 1.0; ratio = 1.0;
// Greek & Cyrilic // Greek & Cyrilic
else if (cp >= 0x03FF && cp <= 0x04FF) { else if (cp >= 0x03FF && cp <= 0x04FF) {
ratio = (_font.capitalization() == QFont::AllUppercase) ? 0.80 : 0.72; ratio = (_font.capitalization() == QFont::AllUppercase) ? 0.75 : 0.68;
if (_font.bold()) if (_font.bold())
ratio *= 1.1; ratio *= 1.1;
// The rest (Latin scripts, Arabic, ...) // The rest (Latin scripts, Arabic, ...)
} else { } else {
ratio = (_font.capitalization() == QFont::AllUppercase) ? 0.75 : 0.63; ratio = (_font.capitalization() == QFont::AllUppercase) ? 0.70 : 0.58;
if (_font.bold()) if (_font.bold())
ratio *= 1.1; ratio *= 1.1;
} }

View File

@ -34,7 +34,7 @@ public:
bool collidesWithItem(const TextItem *other) const; bool collidesWithItem(const TextItem *other) const;
protected: protected:
int avgCharWidth() const; qreal avgCharWidth() const;
private: private:
QString _text; QString _text;

View File

@ -135,7 +135,7 @@ TextPathItem::TextPathItem(const QString &text, const QPainterPath &path,
const QFont &font, int maxAngle, const QRectF &tileRect) const QFont &font, int maxAngle, const QRectF &tileRect)
: TextItem(text, font) : TextItem(text, font)
{ {
int cw = avgCharWidth(); qreal cw = avgCharWidth();
int textWidth = text.size() * cw; int textWidth = text.size() * cw;
if (textWidth > path.length()) if (textWidth > path.length())
return; return;

View File

@ -6,6 +6,25 @@
#define FLAGS (Qt::AlignCenter | Qt::TextWordWrap | Qt::TextDontClip) #define FLAGS (Qt::AlignCenter | Qt::TextWordWrap | Qt::TextDontClip)
static QImage textImage(const QString &text, const QRectF &rect, qreal scale,
const QColor &color, const QFont &font)
{
QImage img(QSize(rect.size().width() * scale, rect.size().height() * scale),
QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::transparent);
QFont f(font);
f.setPixelSize(font.pixelSize() * scale);
QPainter ip(&img);
ip.setPen(color);
ip.setFont(f);
ip.drawText(img.rect(), FLAGS, text);
return img;
}
QRectF TextPointItem::exactBoundingRect() const QRectF TextPointItem::exactBoundingRect() const
{ {
QFontMetrics fm(font()); QFontMetrics fm(font());
@ -26,7 +45,6 @@ QRectF TextPointItem::fuzzyBoundingRect() const
{ {
int limit = font().pixelSize() * _maxWidth; int limit = font().pixelSize() * _maxWidth;
qreal cw = avgCharWidth(); qreal cw = avgCharWidth();
qreal lh = font().pixelSize() * 1.25;
int width = 0, lines = 0; int width = 0, lines = 0;
QStringList l(text().split('\n')); QStringList l(text().split('\n'));
@ -59,7 +77,8 @@ QRectF TextPointItem::fuzzyBoundingRect() const
} }
} }
return QRectF(0, 0, width, lines * lh); return QRectF(0, 0, width, lines > 1 ? lines * font().pixelSize() * 1.3
: font().pixelSize() * 1.5);
} }
@ -132,10 +151,10 @@ void TextPointItem::setPos(const QPointF &pos)
void TextPointItem::paint(QPainter *painter) const void TextPointItem::paint(QPainter *painter) const
{ {
QRectF textRect(_boundingRect); QRectF textRect = (!_icon.isNull() || hasHalo())
? computeTextRect(true) : _boundingRect;
if (!_icon.isNull()) { if (!_icon.isNull()) {
textRect = computeTextRect(true);
#ifdef ENABLE_HIDPI #ifdef ENABLE_HIDPI
painter->drawImage(_pos - QPointF(_icon.width() painter->drawImage(_pos - QPointF(_icon.width()
/ _icon.devicePixelRatioF() / 2, _icon.height() / _icon.devicePixelRatioF() / 2, _icon.height()
@ -147,26 +166,26 @@ void TextPointItem::paint(QPainter *painter) const
} }
if (hasHalo()) { if (hasHalo()) {
QRect ir(textRect.toRect()); const QTransform &t = painter->worldTransform();
QImage img(ir.size(), QImage::Format_ARGB32_Premultiplied); QPoint p((textRect.topLeft() * t.m11()).toPoint());
img.fill(Qt::transparent); QImage img(textImage(text(), textRect, t.m11(), halo().color(), font()));
QPainter ip(&img);
ip.setPen(halo().color());
ip.setFont(font());
ip.drawText(img.rect(), FLAGS, text());
painter->drawImage(ir.x() - 1, ir.y() - 1, img); painter->save();
painter->drawImage(ir.x() + 1, ir.y() + 1, img); painter->resetTransform();
painter->drawImage(ir.x() - 1, ir.y() + 1, img);
painter->drawImage(ir.x() + 1, ir.y() - 1, img);
painter->drawImage(ir.x(), ir.y() - 1, img);
painter->drawImage(ir.x(), ir.y() + 1, img);
painter->drawImage(ir.x() - 1, ir.y(), img);
painter->drawImage(ir.x() + 1, ir.y(), img);
painter->setFont(font()); painter->drawImage(p.x() - 1, p.y() - 1, img);
painter->setPen(pen()); painter->drawImage(p.x() + 1, p.y() + 1, img);
painter->drawText(ir, FLAGS, text()); painter->drawImage(p.x() - 1, p.y() + 1, img);
painter->drawImage(p.x() + 1, p.y() - 1, img);
painter->drawImage(p.x(), p.y() - 1, img);
painter->drawImage(p.x(), p.y() + 1, img);
painter->drawImage(p.x() - 1, p.y(), img);
painter->drawImage(p.x() + 1, p.y(), img);
painter->drawImage(p.x(), p.y(), textImage(text(), textRect, t.m11(),
pen().color(), font()));
painter->restore();
} else { } else {
painter->setFont(font()); painter->setFont(font());
painter->setPen(pen()); painter->setPen(pen());