QTextHtmlParser: Handle fractional font-size pixel values

The CSS spec defines the font-size as being a length, which is a
combination of a real number and a unit. This applies to the 'px'
unit as well, so by treating px values as integers when parsing
we were failing to parse not only '12.5px' but also '12.0px'.

The code now uses QMetaType::fromType<qreal> but then sets the
resulting pixel type on the QFont as an integer, as QFont does
not support fractional pixel sizes.

Other code paths in the CSS parsing machinery use QString::toInt(),
either directly or via intValueHelper() or lengthValue(). The font
code path can potentially be ported over to these other APIs for
consistency, but to keep the patch simple this is left for a
follow-up.

Pick-to: 6.5 6.2 5.15
Change-Id: I972cfe0f3fa3c785efa18c7593d6a497ff28911c
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
(cherry picked from commit 5731e3e185d3a69502b2bc4f1fee48c156b34c3c)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Tor Arne Vestbø 2024-08-11 23:23:40 +02:00 committed by Qt Cherry-pick Bot
parent 893a882151
commit eeb0740f2e
2 changed files with 62 additions and 1 deletions

View File

@ -1157,7 +1157,7 @@ static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAd
} else if (s.endsWith("px"_L1, Qt::CaseInsensitive)) {
s.chop(2);
value.variant = s;
if (value.variant.convert(QMetaType::fromType<int>())) {
if (value.variant.convert(QMetaType::fromType<qreal>())) {
font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
valid = true;
}

View File

@ -50,6 +50,8 @@ private slots:
void gradient();
void extractFontFamily_data();
void extractFontFamily();
void extractFontSize_data();
void extractFontSize();
void extractBorder_data();
void extractBorder();
void noTextDecoration();
@ -1626,6 +1628,65 @@ void tst_QCssParser::extractFontFamily()
QTEST(info.family(), "expectedFamily");
}
void tst_QCssParser::extractFontSize_data()
{
QTest::addColumn<QString>("css");
QTest::addColumn<int>("expectedPixelSize");
QTest::addColumn<int>("expectedPointSize");
QTest::addColumn<qreal>("expectedPointSizeF");
QTest::newRow("integer point size") << "font-size: 12pt" << -1 << 12 << 12.0;
QTest::newRow("float point size round down") << "font-size: 12.3pt" << -1 << 12 << 12.3;
QTest::newRow("float point size midpoint") << "font-size: 12.5pt" << -1 << 13 << 12.5;
QTest::newRow("float point size round up") << "font-size: 12.7pt" << -1 << 13 << 12.7;
QTest::newRow("integer pixel size") << "font-size: 12px" << 12 << -1 << -1.0;
QTest::newRow("float pixel size round down") << "font-size: 12.3px" << 12 << -1 << -1.0;
QTest::newRow("float pixel size midpoint") << "font-size: 12.5px" << 13 << -1 << -1.0;
QTest::newRow("float pixel size round up") << "font-size: 12.7px" << 13 << -1 << -1.0;
QTest::newRow("shorthand integer point size") << "font: 12pt Arial" << -1 << 12 << 12.0;
QTest::newRow("shorthand float point size round down") << "font: 12.3pt Arial" << -1 << 12 << 12.3;
QTest::newRow("shorthand float point size midpoint") << "font: 12.5pt Arial" << -1 << 13 << 12.5;
QTest::newRow("shorthand float point size round up") << "font: 12.7pt Arial" << -1 << 13 << 12.7;
QTest::newRow("shorthand integer pixel size") << "font: 12px Arial" << 12 << -1 << -1.0;
QTest::newRow("shorthand float pixel size round down") << "font: 12.3px Arial" << 12 << -1 << -1.0;
QTest::newRow("shorthand float pixel size midpoint") << "font: 12.5px Arial" << 13 << -1 << -1.0;
QTest::newRow("shorthand float pixel size round up") << "font: 12.7px Arial" << 13 << -1 << -1.0;
}
void tst_QCssParser::extractFontSize()
{
QFETCH(QString, css);
css.prepend("dummy {");
css.append(QLatin1Char('}'));
QCss::Parser parser(css);
QCss::StyleSheet sheet;
QVERIFY(parser.parse(&sheet));
QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1);
QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ?
sheet.styleRules.at(0) : *sheet.nameIndex.begin();
const QList<QCss::Declaration> decls = rule.declarations;
QVERIFY(!decls.isEmpty());
QCss::ValueExtractor extractor(decls);
int adjustment = 0;
QFont font;
extractor.extractFont(&font, &adjustment);
QFETCH(int, expectedPixelSize);
QFETCH(int, expectedPointSize);
QFETCH(qreal, expectedPointSizeF);
QCOMPARE(font.pixelSize(), expectedPixelSize);
QCOMPARE(font.pointSize(), expectedPointSize);
QCOMPARE(font.pointSizeF(), expectedPointSizeF);
}
void tst_QCssParser::extractBorder_data()
{
QTest::addColumn<QString>("css");