summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <[email protected]>2025-03-18 15:11:17 +0100
committerEskil Abrahamsen Blomfeldt <[email protected]>2025-03-25 10:30:31 +0100
commit2b5533af920726723479557356f56d0778bcabd3 (patch)
tree606286c1de3c186d597e7eff4a1a604250244575
parentbec7201f32e797bd6ee38a29853663174f5f705c (diff)
Improve underline drawing for fonts in QPainter
In the underline drawing code in QPainter there were some issues causing First of all, if an underline was very thick, then we would still just offset the drawing by 0.5 (as if it were 1 pixel wide) causing part of the underline to appear on top of the text. The shift here is intended to move the top edge of the underline to the top edge of the pixel where we want to draw it, so we need to offset it by half of the actual line thickness. In addition, fractional line widths look bad when drawn with aliased painting, which is the default. Depending on where the text would be, the thickness of a line might vary. Even if it's very close to an integer, e.g. 1.04 as in one case, then it will still sometimes fill two pixels if it happens to be placed directly between them. To ensure that we always fill the same number of pixels, we round the line thickness to nearest integer when antialiasing is not enabled. Pick-to: 6.8 6.9 Fixes: QTBUG-134626 Change-Id: I95bae3ac16010fc133995e5f9b6c2e5d022e3743 Reviewed-by: Eirik Aavitsland <[email protected]>
-rw-r--r--src/gui/painting/qpainter.cpp12
-rw-r--r--tests/baseline/painting/CMakeLists.txt3
-rw-r--r--tests/baseline/painting/fonts/QtUnderlineTest-Regular.ttfbin0 -> 21692 bytes
-rw-r--r--tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttfbin0 -> 21872 bytes
-rw-r--r--tests/baseline/painting/scripts/text.qps26
-rw-r--r--tests/baseline/painting/tst_baseline_painting.cpp12
6 files changed, 50 insertions, 3 deletions
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 4e8e1d65ecf..f5285a9120f 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -6039,11 +6039,16 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
painter->fillRect(pos.x(), 0, qCeil(width), qMin(wave.height(), descent), wave);
painter->restore();
} else if (underlineStyle != QTextCharFormat::NoUnderline) {
+ const bool isAntialiasing = painter->renderHints().testFlag(QPainter::Antialiasing);
+ if (!isAntialiasing)
+ pen.setWidthF(qMax(fe->lineThickness().round(), QFixed(1)).toReal());
+ const qreal lineThicknessOffset = pen.widthF() / 2.0;
+
// Deliberately ceil the offset to avoid the underline coming too close to
// the text above it, but limit it to stay within descent.
- qreal adjustedUnderlineOffset = std::ceil(underlineOffset) + 0.5;
+ qreal adjustedUnderlineOffset = std::ceil(underlineOffset) + lineThicknessOffset;
if (underlineOffset <= fe->descent().toReal())
- adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - qreal(0.5));
+ adjustedUnderlineOffset = qMin(adjustedUnderlineOffset, fe->descent().toReal() - lineThicknessOffset);
const qreal underlinePos = pos.y() + adjustedUnderlineOffset;
QColor uc = charFormat.underlineColor();
if (uc.isValid())
@@ -6056,6 +6061,9 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
textEngine->addUnderline(painter, underline);
else
painter->drawLine(underline);
+
+ if (!isAntialiasing)
+ pen.setWidthF(fe->lineThickness().toReal());
}
pen.setStyle(Qt::SolidLine);
diff --git a/tests/baseline/painting/CMakeLists.txt b/tests/baseline/painting/CMakeLists.txt
index 86dc752186b..940967a9468 100644
--- a/tests/baseline/painting/CMakeLists.txt
+++ b/tests/baseline/painting/CMakeLists.txt
@@ -8,7 +8,8 @@
# Collect test data
file(GLOB_RECURSE test_data_glob
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
- scripts/*)
+ scripts/*
+ fonts/* )
list(APPEND test_data ${test_data_glob})
if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
diff --git a/tests/baseline/painting/fonts/QtUnderlineTest-Regular.ttf b/tests/baseline/painting/fonts/QtUnderlineTest-Regular.ttf
new file mode 100644
index 00000000000..0b165974abc
--- /dev/null
+++ b/tests/baseline/painting/fonts/QtUnderlineTest-Regular.ttf
Binary files differ
diff --git a/tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttf b/tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttf
new file mode 100644
index 00000000000..b830569a1a4
--- /dev/null
+++ b/tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttf
Binary files differ
diff --git a/tests/baseline/painting/scripts/text.qps b/tests/baseline/painting/scripts/text.qps
index 6bacdfd5e62..5f0576275e8 100644
--- a/tests/baseline/painting/scripts/text.qps
+++ b/tests/baseline/painting/scripts/text.qps
@@ -196,4 +196,30 @@ save
drawText 0 20 "All the effects text drawing"
restore
+translate 0 35
+save
+ setPen black
+ setFont "QtUnderlineTest" 20 normal normal default underline
+ drawText 0 20 "1234"
+restore
+
+translate 0 35.5
+save
+ setPen black
+ setFont "QtUnderlineTest2" 18 normal normal default underline
+ drawText 0 20 "1234"
+restore
+translate 0 35.5
+save
+ setPen black
+ setFont "QtUnderlineTest2" 12 normal normal default underline
+ drawText 0 20 "1234"
+restore
+
+translate 0 35.5
+save
+ setPen black
+ setFont "QtUnderlineTest2" 12 normal normal default underline
+ drawText 0 20 "1234"
+restore
diff --git a/tests/baseline/painting/tst_baseline_painting.cpp b/tests/baseline/painting/tst_baseline_painting.cpp
index d81f4468dcf..7e17926dc25 100644
--- a/tests/baseline/painting/tst_baseline_painting.cpp
+++ b/tests/baseline/painting/tst_baseline_painting.cpp
@@ -19,6 +19,8 @@
#include <QOpenGLPaintDevice>
#endif
+#include <QFontDatabase>
+
#include <algorithm>
#ifndef GL_RGB10
@@ -129,6 +131,16 @@ void tst_Lancelot::initTestCase()
scriptChecksums.insert(fileName, qChecksum(cont));
}
+ QString underlineTestFont1 = QFINDTESTDATA("fonts/QtUnderlineTest-Regular.ttf");
+ QVERIFY(!underlineTestFont1.isEmpty());
+ int id = QFontDatabase::addApplicationFont(underlineTestFont1);
+ QVERIFY(id >= 0);
+
+ QString underlineTestFont2 = QFINDTESTDATA("fonts/QtUnderlineTest2-Regular.ttf");
+ QVERIFY(!underlineTestFont2.isEmpty());
+ id = QFontDatabase::addApplicationFont(underlineTestFont2);
+ QVERIFY(id >= 0);
+
#ifndef QT_NO_OPENGL
initOpenGL();
#endif