diff options
author | Eskil Abrahamsen Blomfeldt <[email protected]> | 2025-03-18 15:11:17 +0100 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <[email protected]> | 2025-03-25 10:30:31 +0100 |
commit | 2b5533af920726723479557356f56d0778bcabd3 (patch) | |
tree | 606286c1de3c186d597e7eff4a1a604250244575 | |
parent | bec7201f32e797bd6ee38a29853663174f5f705c (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.cpp | 12 | ||||
-rw-r--r-- | tests/baseline/painting/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/baseline/painting/fonts/QtUnderlineTest-Regular.ttf | bin | 0 -> 21692 bytes | |||
-rw-r--r-- | tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttf | bin | 0 -> 21872 bytes | |||
-rw-r--r-- | tests/baseline/painting/scripts/text.qps | 26 | ||||
-rw-r--r-- | tests/baseline/painting/tst_baseline_painting.cpp | 12 |
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 Binary files differnew file mode 100644 index 00000000000..0b165974abc --- /dev/null +++ b/tests/baseline/painting/fonts/QtUnderlineTest-Regular.ttf diff --git a/tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttf b/tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttf Binary files differnew file mode 100644 index 00000000000..b830569a1a4 --- /dev/null +++ b/tests/baseline/painting/fonts/QtUnderlineTest2-Regular.ttf 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 |