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>(); + 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>(); + 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 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::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 @@ -1809,6 +1840,55 @@ void QTextCharFormat::setUnderlineStyle(UnderlineStyle style) \sa font(), QFont::hintingPreference() */ +/*! + \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 &fontFeatures) +{ + setProperty(FontFeatures, QVariant::fromValue(fontFeatures)); +} + +/*! + \since 6.11 + + Gets the typographical features of the text format's font. + + \sa setFontFeatures() +*/ +QHash QTextCharFormat::fontFeatures() const +{ + return property(FontFeatures).value>(); +} + +/*! + \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 &fontVariableAxes) +{ + setProperty(FontVariableAxes, QVariant::fromValue(fontVariableAxes)); +} + +/*! + \since 6.11 + + Gets the variable axes of the text format's font. + + \sa setFontVariableAxes() +*/ +QHash QTextCharFormat::fontVariableAxes() const +{ + return property(FontVariableAxes).value>(); +} + + /*! \fn QPen QTextCharFormat::textOutline() const @@ -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 fontFeatures; + for (QFont::Tag tag : tags) + fontFeatures.insert(tag, font.featureValue(tag)); + setFontFeatures(fontFeatures); + } + if (mask & QFont::VariableAxesResolved) { + const auto tags = font.variableAxisTags(); + + QHash 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 #include #include +#include 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(intProperty(FontHintingPreference)); } + void setFontFeatures(const QHash &fontFeatures); + QHash fontFeatures() const; + void setFontVariableAxes(const QHash &fontVariableAxes); + QHash 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 features = format.fontFeatures(); + QCOMPARE(features.size(), 2); + QCOMPARE(features.value("abcd"), 1234); + QCOMPARE(features.value("efgh"), 5678); + } + + { + QTextCharFormat format; + + QHash 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 axes = format.fontVariableAxes(); + QCOMPARE(axes.size(), 2); + QCOMPARE(axes.value("abcd"), 12.25); + QCOMPARE(axes.value("efgh"), 13.25); + } + + { + QTextCharFormat format; + + QHash 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 properties = other.properties(); + QVERIFY(properties.contains(QTextFormat::FontFeatures)); + + auto features = other.property(QTextFormat::FontFeatures).value>(); + 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 properties = other.properties(); + QVERIFY(!properties.contains(QTextFormat::FontFeatures)); + QVERIFY(!properties.contains(QTextFormat::OldTextUnderlineColor)); + } + } } #endif // QT_NO_DATASTREAM