summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2021-07-16 13:44:19 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-08-10 19:34:15 +0000
commit4e6b16a24813de68925d3033c4cc2cbbe3b39bc9 (patch)
treeb20ed10cf8a61473a9123e9f118e3d40d009ef56
parent11e5f1fca6b5229a00ad54abb29b8213e4e54a8f (diff)
Implement missing support for 'em' and 'ex' lengths in style sheet
The Qt style sheet reference claimed that Length properties can be specified in 'em' or 'ex' units, but that was never implemented. Add the missing implementation. Since the sizes depend on the size of the font of the current element, we cannot convert the units in the CSS parser, but have to do so in the QRenderRule constructor, where we can make a decision about which font to use if the style sheet itself doesn't specify a font. Fall back to the widget font if possible; otherwise it will be the application default font. The implementation translates em into QFontMetrics.height, identical to what is already done in the QCssParser. This is in line with the CSS specification, but contradicts our previous documentation which stated that 'em' means "width of M". Fix the documentation. Fixes: QTBUG-8096 Change-Id: I145e2504ae3b19101a0d0dd63653466b6c2cec1d Done-with: Cristian Maureira-Fredes <Cristian.Maureira-Fredes@qt.io> Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io> (cherry picked from commit 33f9591e378a2162378d8be5e75a47adf034536b) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc3
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp72
-rw-r--r--tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp28
3 files changed, 80 insertions, 23 deletions
diff --git a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
index f4edfb92dc..44f20ca0ae 100644
--- a/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
+++ b/src/widgets/doc/src/widgets-and-layouts/stylesheet.qdoc
@@ -3027,7 +3027,8 @@
\list
\li \c px: pixels
\li \c pt: the size of one point (i.e., 1/72 of an inch)
- \li \c em: the em width of the font (i.e., the width of 'M')
+ \li \c em: the size relative to the font size of the element
+ (e.g., 2em means 2 times the size of the font)
\li \c ex: the x-height of the font (i.e., the height of 'x')
\endlist
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index 728dcd8c12..a6d0c01869 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -1051,31 +1051,59 @@ QRenderRule::QRenderRule(const QList<Declaration> &declarations, const QObject *
for (int i = 0; i < numKnownStyleHints; i++) {
QLatin1String styleHint(knownStyleHints[i]);
if (decl.d->property.compare(styleHint) == 0) {
- QString hintName = QString(styleHint);
- QVariant hintValue;
- if (hintName.endsWith(QLatin1String("alignment"))) {
- hintValue = (int) decl.alignmentValue();
- } else if (hintName.endsWith(QLatin1String("color"))) {
- hintValue = (int) decl.colorValue().rgba();
- } else if (hintName.endsWith(QLatin1String("size"))) {
- hintValue = decl.sizeValue();
- } else if (hintName.endsWith(QLatin1String("icon"))) {
- hintValue = decl.iconValue();
- } else if (hintName == QLatin1String("button-layout")
- && decl.d->values.count() != 0 && decl.d->values.at(0).type == Value::String) {
- hintValue = subControlLayout(decl.d->values.at(0).variant.toString());
- } else {
- int integer;
- decl.intValue(&integer);
- hintValue = integer;
- }
- styleHints[decl.d->property] = hintValue;
- knownStyleHint = true;
- break;
+ QString hintName = QString(styleHint);
+ QVariant hintValue;
+ if (hintName.endsWith(QLatin1String("alignment"))) {
+ hintValue = (int) decl.alignmentValue();
+ } else if (hintName.endsWith(QLatin1String("color"))) {
+ hintValue = (int) decl.colorValue().rgba();
+ } else if (hintName.endsWith(QLatin1String("size"))) {
+ // Check only for the 'em' case
+ const QString valueString = decl.d->values.at(0).variant.toString();
+ const bool isEmSize = valueString.endsWith(u"em", Qt::CaseInsensitive);
+ if (isEmSize || valueString.endsWith(u"ex", Qt::CaseInsensitive)) {
+ // 1em == size of font; 1ex == xHeight of font
+ // See lengthValueFromData helper in qcssparser.cpp
+ QFont fontForSize(font);
+ // if no font is specified, then use the widget font if possible
+ if (const QWidget *widget; !hasFont && (widget = qobject_cast<const QWidget*>(object)))
+ fontForSize = widget->font();
+
+ const QFontMetrics fontMetrics(fontForSize);
+ qreal pixelSize = isEmSize ? fontMetrics.height() : fontMetrics.xHeight();
+
+ // Transform size according to the 'em'/'ex' value
+ qreal emexSize = {};
+ if (decl.realValue(&emexSize, isEmSize ? "em" : "ex") && emexSize > 0) {
+ pixelSize *= emexSize;
+ const QSizeF newSize(pixelSize, pixelSize);
+ decl.d->parsed = QVariant::fromValue<QSizeF>(newSize);
+ hintValue = newSize;
+ } else {
+ qWarning("Invalid '%s' size for %s. Skipping.",
+ isEmSize ? "em" : "ex", qPrintable(valueString));
+ }
+ } else {
+ // Normal case where we receive a 'px' or 'pt' unit
+ hintValue = decl.sizeValue();
+ }
+ } else if (hintName.endsWith(QLatin1String("icon"))) {
+ hintValue = decl.iconValue();
+ } else if (hintName == QLatin1String("button-layout")
+ && decl.d->values.count() != 0 && decl.d->values.at(0).type == Value::String) {
+ hintValue = subControlLayout(decl.d->values.at(0).variant.toString());
+ } else {
+ int integer;
+ decl.intValue(&integer);
+ hintValue = integer;
+ }
+ styleHints[decl.d->property] = hintValue;
+ knownStyleHint = true;
+ break;
}
}
if (!knownStyleHint)
- qDebug("Unknown property %s", qPrintable(decl.d->property));
+ qWarning("Unknown property %s", qPrintable(decl.d->property));
}
}
diff --git a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
index 0e27a87467..c742a6cf4e 100644
--- a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
+++ b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp
@@ -2338,12 +2338,40 @@ void tst_QStyleSheetStyle::iconSizes_data()
smallFont.setPointSizeF(9.0);
QFont largeFont;
largeFont.setPointSizeF(24.0);
+ QFont hugeFont;
+ hugeFont.setPointSizeF(40.0);
QTest::addRow("default") << QString() << QFont() << QSize(defaultSize, defaultSize);
QTest::addRow("pixels") << "icon-size: 50px" << QFont() << QSize(50, 50);
QTest::addRow("points") << "icon-size: 20pt" << QFont() << QSize(15, 15);
QTest::addRow("pixels with font") << "icon-size: 50px" << smallFont << QSize(50, 50);
QTest::addRow("points with font") << "icon-size: 20pt" << largeFont << QSize(15, 15);
+
+ const QFontMetrics defaultMetrics{QFont()};
+ const QFontMetrics smallMetrics(smallFont);
+ const QFontMetrics largeMetrics(largeFont);
+ const QFontMetrics hugeMetrics(hugeFont);
+ QTest::addRow("1em, default font") << "icon-size: 1em"
+ << QFont() << QSize(defaultMetrics.height(), defaultMetrics.height());
+ QTest::addRow("1em, small font") << "icon-size: 1em"
+ << smallFont << QSize(smallMetrics.height(), smallMetrics.height());
+ QTest::addRow("1em, large font") << "icon-size: 1em"
+ << largeFont << QSize(largeMetrics.height(), largeMetrics.height());
+ QTest::addRow("1.5em, lage font") << "icon-size: 1.5em"
+ << largeFont << QSize(largeMetrics.height(), largeMetrics.height()) * 1.5;
+ QTest::addRow("2em with styled font") << "font-size: 40pt; icon-size: 2em"
+ << QFont() << QSize(hugeMetrics.height(), hugeMetrics.height()) * 2;
+
+ QTest::addRow("1ex, default font") << "icon-size: 1ex"
+ << QFont() << QSize(defaultMetrics.xHeight(), defaultMetrics.xHeight());
+ QTest::addRow("1ex, small font") << "icon-size: 1ex"
+ << smallFont << QSize(smallMetrics.xHeight(), smallMetrics.xHeight());
+ QTest::addRow("1ex, large font") << "icon-size: 1ex"
+ << largeFont << QSize(largeMetrics.xHeight(), largeMetrics.xHeight());
+ QTest::addRow("1.5ex, lage font") << "icon-size: 1.5ex"
+ << largeFont << QSize(largeMetrics.xHeight(), largeMetrics.xHeight()) * 1.5;
+ QTest::addRow("2ex with styled font") << "font-size: 40pt; icon-size: 2ex"
+ << QFont() << QSize(hugeMetrics.xHeight(), hugeMetrics.xHeight()) * 2;
}
void tst_QStyleSheetStyle::iconSizes()