diff options
author | Eskil Abrahamsen Blomfeldt <[email protected]> | 2025-06-02 12:38:55 +0200 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <[email protected]> | 2025-06-06 16:27:54 +0200 |
commit | fb89d498a967a53b4347f6db5f9a5426d60d2a01 (patch) | |
tree | ca86423ead5aabea73486baedccf02f0567928ec | |
parent | 9b9a2398f30b6c35ef6be3ce929c352afb682910 (diff) |
Add support for font features and variable axes to QTextCharFormat
These can be set on the font directly, but had not been added to
QTextCharFormat, so there would be no way to override them by
formatting in a rich text document.
Fixes: QTBUG-134060
Change-Id: I4494e24cb9b99d84fb376ba895e2461fc3cd054b
Reviewed-by: Eirik Aavitsland <[email protected]>
-rw-r--r-- | src/corelib/serialization/qdatastream.h | 2 | ||||
-rw-r--r-- | src/gui/text/qtextformat.cpp | 112 | ||||
-rw-r--r-- | src/gui/text/qtextformat.h | 10 | ||||
-rw-r--r-- | tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp | 1 | ||||
-rw-r--r-- | tests/auto/gui/text/qtextformat/tst_qtextformat.cpp | 152 |
5 files changed, 267 insertions, 10 deletions
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h index ea8ab1f16f0..aed3888b5c6 100644 --- a/src/corelib/serialization/qdatastream.h +++ b/src/corelib/serialization/qdatastream.h @@ -91,7 +91,7 @@ public: Qt_6_8 = Qt_6_7, Qt_6_9 = Qt_6_7, Qt_6_10 = 23, - Qt_6_11 = Qt_6_10, + Qt_6_11 = 24, Qt_DefaultCompiledVersion = Qt_6_11 #if QT_VERSION >= QT_VERSION_CHECK(6, 12, 0) #error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 73b0e769169..06ae00123f0 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -388,6 +388,20 @@ void QTextFormatPrivate::recalcFont() const case QTextFormat::FontKerning: f.setKerning(props.at(i).value.toBool()); break; + case QTextFormat::FontFeatures: + { + const auto fontFeatures = props.at(i).value.value<QHash<QFont::Tag, quint32>>(); + for (auto it = fontFeatures.constBegin(); it != fontFeatures.constEnd(); ++it) + f.setFeature(it.key(), it.value()); + break; + } + case QTextFormat::FontVariableAxes: + { + const auto fontVariableAxes = props.at(i).value.value<QHash<QFont::Tag, float>>(); + for (auto it = fontVariableAxes.constBegin(); it != fontVariableAxes.constEnd(); ++it) + f.setVariableAxis(it.key(), it.value()); + break; + } default: break; } @@ -404,6 +418,16 @@ void QTextFormatPrivate::recalcFont() const Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QTextFormat &fmt) { QMap<int, QVariant> properties = fmt.properties(); + if (stream.version() < QDataStream::Qt_6_11) { + auto it = properties.constFind(QTextFormat::FontFeatures); + if (it != properties.cend()) + properties.erase(it); + + it = properties.constFind(QTextFormat::FontVariableAxes); + if (it != properties.cend()) + properties.erase(it); + } + if (stream.version() < QDataStream::Qt_6_0) { auto it = properties.constFind(QTextFormat::FontLetterSpacingType); if (it != properties.cend()) { @@ -447,14 +471,17 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt) for (QMap<qint32, QVariant>::ConstIterator it = properties.constBegin(); it != properties.constEnd(); ++it) { qint32 key = it.key(); - if (key == QTextFormat::OldFontLetterSpacingType) - key = QTextFormat::FontLetterSpacingType; - else if (key == QTextFormat::OldFontStretch) - key = QTextFormat::FontStretch; - else if (key == QTextFormat::OldTextUnderlineColor) - key = QTextFormat::TextUnderlineColor; - else if (key == QTextFormat::OldFontFamily) - key = QTextFormat::FontFamilies; + + if (stream.version() < QDataStream::Qt_6_0) { + if (key == QTextFormat::OldFontLetterSpacingType) + key = QTextFormat::FontLetterSpacingType; + else if (key == QTextFormat::OldFontStretch) + key = QTextFormat::FontStretch; + else if (key == QTextFormat::OldTextUnderlineColor) + key = QTextFormat::TextUnderlineColor; + else if (key == QTextFormat::OldFontFamily) + key = QTextFormat::FontFamilies; + } fmt.d->insertProperty(key, it.value()); } @@ -653,6 +680,10 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextTableCellFormat & \value FontKerning Specifies whether the font has kerning turned on. \value FontHintingPreference Controls the use of hinting according to values of the QFont::HintingPreference enum. + \value FontFeatures [since 6.11] Assigns integer numbers to typographical features. See + \l{QFont::setFeature()} for additional information. + \value FontVariableAxes [since 6.11] Assigns floating point numbers to variable axes in variable + fonts. See \l{QFont::setVariableAxis()} for additional information. \omitvalue FirstFontProperty \omitvalue LastFontProperty @@ -1810,6 +1841,55 @@ void QTextCharFormat::setUnderlineStyle(UnderlineStyle style) */ /*! + \since 6.11 + + Sets the typographical features of the text format's font to be \a fontFeatures. + + \sa QFont::setFeature() +*/ +void QTextCharFormat::setFontFeatures(const QHash<QFont::Tag, quint32> &fontFeatures) +{ + setProperty(FontFeatures, QVariant::fromValue(fontFeatures)); +} + +/*! + \since 6.11 + + Gets the typographical features of the text format's font. + + \sa setFontFeatures() +*/ +QHash<QFont::Tag, quint32> QTextCharFormat::fontFeatures() const +{ + return property(FontFeatures).value<QHash<QFont::Tag, quint32>>(); +} + +/*! + \since 6.11 + + Sets the variable axes of the text format's font to be \a fontVariableAxes. + + \sa QFont::setVariableAxis() +*/ +void QTextCharFormat::setFontVariableAxes(const QHash<QFont::Tag, float> &fontVariableAxes) +{ + setProperty(FontVariableAxes, QVariant::fromValue(fontVariableAxes)); +} + +/*! + \since 6.11 + + Gets the variable axes of the text format's font. + + \sa setFontVariableAxes() +*/ +QHash<QFont::Tag, float> QTextCharFormat::fontVariableAxes() const +{ + return property(FontVariableAxes).value<QHash<QFont::Tag, float>>(); +} + + +/*! \fn QPen QTextCharFormat::textOutline() const Returns the pen used to draw the outlines of characters in this format. @@ -2145,6 +2225,22 @@ void QTextCharFormat::setFont(const QFont &font, FontPropertiesInheritanceBehavi setFontHintingPreference(font.hintingPreference()); if (mask & QFont::KerningResolved) setFontKerning(font.kerning()); + if (mask & QFont::FeaturesResolved) { + const auto tags = font.featureTags(); + + QHash<QFont::Tag, quint32> fontFeatures; + for (QFont::Tag tag : tags) + fontFeatures.insert(tag, font.featureValue(tag)); + setFontFeatures(fontFeatures); + } + if (mask & QFont::VariableAxesResolved) { + const auto tags = font.variableAxisTags(); + + QHash<QFont::Tag, float> fontVariableAxes; + for (QFont::Tag tag : tags) + fontVariableAxes.insert(tag, font.variableAxisValue(tag)); + setFontVariableAxes(fontVariableAxes); + } } /*! diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index 2fa86ed0d1b..d521968ad6c 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -14,6 +14,7 @@ #include <QtCore/qlist.h> #include <QtCore/qshareddata.h> #include <QtCore/qvariant.h> +#include <QtCore/qhash.h> QT_BEGIN_NAMESPACE @@ -159,7 +160,9 @@ public: FontStrikeOut = 0x2007, FontFixedPitch = 0x2008, FontPixelSize = 0x2009, - LastFontProperty = FontPixelSize, + FontFeatures = 0x2010, // Note: Same as OldTextUnderlineColor + FontVariableAxes = 0x2011, + LastFontProperty = FontVariableAxes, TextUnderlineColor = 0x2020, TextVerticalAlignment = 0x2021, @@ -518,6 +521,11 @@ public: return static_cast<QFont::HintingPreference>(intProperty(FontHintingPreference)); } + void setFontFeatures(const QHash<QFont::Tag, quint32> &fontFeatures); + QHash<QFont::Tag, quint32> fontFeatures() const; + void setFontVariableAxes(const QHash<QFont::Tag, float> &fontVariableAxes); + QHash<QFont::Tag, float> fontVariableAxes() const; + inline void setFontKerning(bool enable) { setProperty(FontKerning, enable); } inline bool fontKerning() const diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp index 37cc4252247..1abd2939c43 100644 --- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp @@ -301,6 +301,7 @@ static constexpr int NColorRoles[] = { QPalette::Accent + 1, // Qt_6_6 QPalette::Accent + 1, // Qt_6_7 QPalette::Accent + 1, // Qt_6_10 + QPalette::Accent + 1, // Qt_6_11 }; // +1, because we start from "No Version" diff --git a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp index 6c6145561d8..e71ea6a732c 100644 --- a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp +++ b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp @@ -45,6 +45,8 @@ private slots: void setFont_collection_data(); void setFont_collection(); void clearCollection(); + void setFontFeatures(); + void setFontVariableAxes(); #ifndef QT_NO_DATASTREAM void dataStreamCompatibility(); @@ -667,6 +669,89 @@ void tst_QTextFormat::clearCollection() QCOMPARE(collection.defaultFont(), f); // kept, QTextDocument::clear or setPlainText should not reset the font set by setDefaultFont } +void tst_QTextFormat::setFontFeatures() +{ + { + QFont font; + font.setFeature("abcd", 1234); + font.setFeature("efgh", 5678); + + QTextCharFormat format; + format.setFont(font); + + QFont resolvedFont = format.font(); + QCOMPARE(resolvedFont.featureTags().size(), 2); + QCOMPARE(resolvedFont.featureValue("abcd"), 1234); + QCOMPARE(resolvedFont.featureValue("efgh"), 5678); + + QHash<QFont::Tag, quint32> features = format.fontFeatures(); + QCOMPARE(features.size(), 2); + QCOMPARE(features.value("abcd"), 1234); + QCOMPARE(features.value("efgh"), 5678); + } + + { + QTextCharFormat format; + + QHash<QFont::Tag, quint32> features; + features.insert("abcd", 4321); + features.insert("efgh", 8765); + format.setFontFeatures(features); + + QFont resolvedFont = format.font(); + QCOMPARE(resolvedFont.featureTags().size(), 2); + QCOMPARE(resolvedFont.featureValue("abcd"), 4321); + QCOMPARE(resolvedFont.featureValue("efgh"), 8765); + + features = format.fontFeatures(); + QCOMPARE(features.size(), 2); + QCOMPARE(features.value("abcd"), 4321); + QCOMPARE(features.value("efgh"), 8765); + } +} + +void tst_QTextFormat::setFontVariableAxes() +{ + { + QFont font; + font.setVariableAxis("abcd", 12.25); + font.setVariableAxis("efgh", 13.25); + + QTextCharFormat format; + format.setFont(font); + + QFont resolvedFont = format.font(); + QCOMPARE(resolvedFont.variableAxisTags().size(), 2); + QCOMPARE(resolvedFont.variableAxisValue("abcd"), 12.25); + QCOMPARE(resolvedFont.variableAxisValue("efgh"), 13.25); + + QHash<QFont::Tag, float> axes = format.fontVariableAxes(); + QCOMPARE(axes.size(), 2); + QCOMPARE(axes.value("abcd"), 12.25); + QCOMPARE(axes.value("efgh"), 13.25); + } + + { + QTextCharFormat format; + + QHash<QFont::Tag, float> axes; + axes.insert("abcd", 12.25); + axes.insert("efgh", 13.25); + format.setFontVariableAxes(axes); + + QFont resolvedFont = format.font(); + QCOMPARE(resolvedFont.variableAxisTags().size(), 2); + QCOMPARE(resolvedFont.variableAxisValue("abcd"), 12.25); + QCOMPARE(resolvedFont.variableAxisValue("efgh"), 13.25); + + axes = format.fontVariableAxes(); + QCOMPARE(axes.size(), 2); + QCOMPARE(axes.value("abcd"), 12.25); + QCOMPARE(axes.value("efgh"), 13.25); + } + +} + #ifndef QT_NO_DATASTREAM void tst_QTextFormat::dataStreamCompatibility() { @@ -795,6 +880,73 @@ void tst_QTextFormat::dataStreamCompatibility() } } + // Don't mix up FontFeatures and OldTextUnderlineColor + memory.clear(); + { + { + QBuffer buffer(&memory); + buffer.open(QIODevice::WriteOnly); + + QFont font; + font.setFeature("abcd", 1234); + + QTextCharFormat format; + format.setFont(font); + + QDataStream stream(&buffer); + + stream << format; + } + + { + QBuffer buffer(&memory); + buffer.open(QIODevice::ReadOnly); + + QDataStream stream(&buffer); + + QTextFormat other; + stream >> other; + + QMap<int, QVariant> properties = other.properties(); + QVERIFY(properties.contains(QTextFormat::FontFeatures)); + + auto features = other.property(QTextFormat::FontFeatures).value<QHash<QFont::Tag, quint32>>(); + QCOMPARE(features.value("abcd"), 1234); + } + } + + memory.clear(); + { + { + QBuffer buffer(&memory); + buffer.open(QIODevice::WriteOnly); + + QFont font; + font.setFeature("abcd", 1234); + + QTextCharFormat format; + format.setFont(font); + + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_15); + + stream << format; + } + + { + QBuffer buffer(&memory); + buffer.open(QIODevice::ReadOnly); + + QDataStream stream(&buffer); + stream.setVersion(QDataStream::Qt_5_15); + + QTextFormat other; + stream >> other; + QMap<int, QVariant> properties = other.properties(); + QVERIFY(!properties.contains(QTextFormat::FontFeatures)); + QVERIFY(!properties.contains(QTextFormat::OldTextUnderlineColor)); + } + } } #endif // QT_NO_DATASTREAM |