diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 641a2ceb8a..d2b91c1f9f 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -1879,36 +1879,93 @@ QStringList QTextCharFormat::anchorNames() const */ /*! + \enum QTextCharFormat::FontPropertiesInheritanceBehavior + \since 5.3 + + This enum specifies how the setFont() function should behave with + respect to unset font properties. + + \value FontPropertiesSpecifiedOnly If a property is not explicitly set, do not + change the text format's property value. + \value FontPropertiesAll If a property is not explicitly set, override the + text format's property with a default value. + + \sa setFont() +*/ + +/*! + \overload + Sets the text format's \a font. + + \sa font() */ void QTextCharFormat::setFont(const QFont &font) { - setFontFamily(font.family()); + setFont(font, FontPropertiesAll); +} - const qreal pointSize = font.pointSizeF(); - if (pointSize > 0) { - setFontPointSize(pointSize); - } else { - const int pixelSize = font.pixelSize(); - if (pixelSize > 0) - setProperty(QTextFormat::FontPixelSize, pixelSize); +/*! + \since 5.3 + + Sets the text format's \a font. + + If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that + has not been explicitly set is treated like as it were set with default value; + If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that + has not been explicitly set is ignored and the respective property value + remains unchanged. + + \sa font() +*/ +void QTextCharFormat::setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior) +{ + const uint mask = behavior == FontPropertiesAll ? uint(QFont::AllPropertiesResolved) + : font.resolve(); + + if (mask & QFont::FamilyResolved) + setFontFamily(font.family()); + if (mask & QFont::SizeResolved) { + const qreal pointSize = font.pointSizeF(); + if (pointSize > 0) { + setFontPointSize(pointSize); + } else { + const int pixelSize = font.pixelSize(); + if (pixelSize > 0) + setProperty(QTextFormat::FontPixelSize, pixelSize); + } } - setFontWeight(font.weight()); - setFontItalic(font.italic()); - setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline); - setFontOverline(font.overline()); - setFontStrikeOut(font.strikeOut()); - setFontFixedPitch(font.fixedPitch()); - setFontCapitalization(font.capitalization()); - setFontWordSpacing(font.wordSpacing()); - setFontLetterSpacingType(font.letterSpacingType()); - setFontLetterSpacing(font.letterSpacing()); - setFontStretch(font.stretch()); - setFontStyleHint(font.styleHint()); - setFontStyleStrategy(font.styleStrategy()); - setFontHintingPreference(font.hintingPreference()); - setFontKerning(font.kerning()); + if (mask & QFont::WeightResolved) + setFontWeight(font.weight()); + if (mask & QFont::StyleResolved) + setFontItalic(font.style() != QFont::StyleNormal); + if (mask & QFont::UnderlineResolved) + setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline); + if (mask & QFont::OverlineResolved) + setFontOverline(font.overline()); + if (mask & QFont::StrikeOutResolved) + setFontStrikeOut(font.strikeOut()); + if (mask & QFont::FixedPitchResolved) + setFontFixedPitch(font.fixedPitch()); + if (mask & QFont::CapitalizationResolved) + setFontCapitalization(font.capitalization()); + if (mask & QFont::LetterSpacingResolved) + setFontWordSpacing(font.wordSpacing()); + if (mask & QFont::LetterSpacingResolved) { + setFontLetterSpacingType(font.letterSpacingType()); + setFontLetterSpacing(font.letterSpacing()); + } + if (mask & QFont::StretchResolved) + setFontStretch(font.stretch()); + if (mask & QFont::StyleHintResolved) + setFontStyleHint(font.styleHint()); + if (mask & QFont::StyleStrategyResolved) + setFontStyleStrategy(font.styleStrategy()); + if (mask & QFont::HintingPreferenceResolved) + setFontHintingPreference(font.hintingPreference()); + if (mask & QFont::KerningResolved) + setFontKerning(font.kerning()); } /*! diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index c04ac3876b..1906a8a0c2 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -408,7 +408,13 @@ public: QTextCharFormat(); bool isValid() const { return isCharFormat(); } - void setFont(const QFont &font); + + enum FontPropertiesInheritanceBehavior { + FontPropertiesSpecifiedOnly, + FontPropertiesAll + }; + void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior); + void setFont(const QFont &font); // ### Qt6: Merge with above QFont font() const; inline void setFontFamily(const QString &family) diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index 3cb61b9eae..e8a02c44b2 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -1361,33 +1361,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector QFont f; int adjustment = -255; extractor.extractFont(&f, &adjustment); - if (f.resolve() & QFont::SizeResolved) { - if (f.pointSize() > 0) { - charFormat.setFontPointSize(f.pointSize()); - } else if (f.pixelSize() > 0) { - charFormat.setProperty(QTextFormat::FontPixelSize, f.pixelSize()); - } - } - if (f.resolve() & QFont::StyleResolved) - charFormat.setFontItalic(f.style() != QFont::StyleNormal); - - if (f.resolve() & QFont::WeightResolved) - charFormat.setFontWeight(f.weight()); - - if (f.resolve() & QFont::FamilyResolved) - charFormat.setFontFamily(f.family()); - - if (f.resolve() & QFont::UnderlineResolved) - charFormat.setUnderlineStyle(f.underline() ? QTextCharFormat::SingleUnderline : QTextCharFormat::NoUnderline); - - if (f.resolve() & QFont::OverlineResolved) - charFormat.setFontOverline(f.overline()); - - if (f.resolve() & QFont::StrikeOutResolved) - charFormat.setFontStrikeOut(f.strikeOut()); - - if (f.resolve() & QFont::CapitalizationResolved) - charFormat.setFontCapitalization(f.capitalization()); + charFormat.setFont(f, QTextCharFormat::FontPropertiesSpecifiedOnly); if (adjustment >= -1) charFormat.setProperty(QTextFormat::FontSizeAdjustment, adjustment); diff --git a/tests/auto/gui/text/qtextformat/qtextformat.pro b/tests/auto/gui/text/qtextformat/qtextformat.pro index b137dac9eb..c64d266916 100644 --- a/tests/auto/gui/text/qtextformat/qtextformat.pro +++ b/tests/auto/gui/text/qtextformat/qtextformat.pro @@ -1,5 +1,5 @@ CONFIG += testcase CONFIG += parallel_test TARGET = tst_qtextformat -QT += testlib +QT += testlib core-private gui-private SOURCES += tst_qtextformat.cpp diff --git a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp index 1eb073d3b4..beb5069f06 100644 --- a/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp +++ b/tests/auto/gui/text/qtextformat/tst_qtextformat.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,10 @@ private slots: void getSetTabs(); void testTabsUsed(); void testFontStyleSetters(); + void setFont_data(); + void setFont(); + void setFont_collection_data(); + void setFont_collection(); }; /*! \internal @@ -410,5 +415,243 @@ void tst_QTextFormat::testFontStyleSetters() QCOMPARE(format.font().kerning(), false); } +Q_DECLARE_METATYPE(QTextCharFormat) + +void tst_QTextFormat::setFont_data() +{ + QTest::addColumn("format1"); + QTest::addColumn("format2"); + QTest::addColumn("overrideAll"); + + QTextCharFormat format1; + format1.setFontStyleHint(QFont::Serif); + format1.setFontStyleStrategy(QFont::PreferOutline); + format1.setFontCapitalization(QFont::AllUppercase); + format1.setFontKerning(true); + + { + QTest::newRow("noop|override") << format1 << format1 << true; + QTest::newRow("noop|inherit") << format1 << format1 << false; + } + + { + QTextCharFormat format2; + format2.setFontStyleHint(QFont::SansSerif); + format2.setFontStyleStrategy(QFont::PreferAntialias); + format2.setFontCapitalization(QFont::MixedCase); + format2.setFontKerning(false); + + QTest::newRow("coverage|override") << format1 << format2 << true; + QTest::newRow("coverage|inherit") << format1 << format2 << false; + } + + { + QTextCharFormat format2; + format2.setFontStyleHint(QFont::SansSerif); + format2.setFontStyleStrategy(QFont::PreferAntialias); + + QTest::newRow("partial|override") << format1 << format2 << true; + QTest::newRow("partial|inherit") << format1 << format2 << false; + } +} + +void tst_QTextFormat::setFont() +{ + QFETCH(QTextCharFormat, format1); + QFETCH(QTextCharFormat, format2); + QFETCH(bool, overrideAll); + + QTextCharFormat f; + + f.merge(format1); + QCOMPARE((int)f.fontStyleHint(), (int)format1.fontStyleHint()); + QCOMPARE((int)f.fontStyleStrategy(), (int)format1.fontStyleStrategy()); + QCOMPARE((int)f.fontCapitalization(), (int)format1.fontCapitalization()); + QCOMPARE(f.fontKerning(), format1.fontKerning()); + + QCOMPARE((int)f.font().styleHint(), (int)f.fontStyleHint()); + QCOMPARE((int)f.font().styleStrategy(), (int)f.fontStyleStrategy()); + QCOMPARE((int)f.font().capitalization(), (int)f.fontCapitalization()); + QCOMPARE(f.font().kerning(), f.fontKerning()); + + f.merge(format2); + QCOMPARE((int)f.font().styleHint(), (int)f.fontStyleHint()); + QCOMPARE((int)f.font().styleStrategy(), (int)f.fontStyleStrategy()); + QCOMPARE((int)f.font().capitalization(), (int)f.fontCapitalization()); + QCOMPARE(f.font().kerning(), f.fontKerning()); + + if (format2.hasProperty(QTextFormat::FontStyleHint)) + QCOMPARE((int)f.font().styleHint(), (int)format2.fontStyleHint()); + else + QCOMPARE((int)f.font().styleHint(), (int)format1.fontStyleHint()); + if (format2.hasProperty(QTextFormat::FontStyleStrategy)) + QCOMPARE((int)f.font().styleStrategy(), (int)format2.fontStyleStrategy()); + else + QCOMPARE((int)f.font().styleStrategy(), (int)format1.fontStyleStrategy()); + if (format2.hasProperty(QTextFormat::FontCapitalization)) + QCOMPARE((int)f.font().capitalization(), (int)format2.fontCapitalization()); + else + QCOMPARE((int)f.font().capitalization(), (int)format1.fontCapitalization()); + if (format2.hasProperty(QTextFormat::FontKerning)) + QCOMPARE(f.font().kerning(), format2.fontKerning()); + else + QCOMPARE(f.font().kerning(), format1.fontKerning()); + + + QFont font1 = format1.font(); + QFont font2 = format2.font(); + + f = QTextCharFormat(); + + { + QTextCharFormat tmp; + tmp.setFont(font1, overrideAll ? QTextCharFormat::FontPropertiesAll + : QTextCharFormat::FontPropertiesSpecifiedOnly); + f.merge(tmp); + } + QCOMPARE((int)f.fontStyleHint(), (int)format1.fontStyleHint()); + QCOMPARE((int)f.fontStyleStrategy(), (int)format1.fontStyleStrategy()); + QCOMPARE((int)f.fontCapitalization(), (int)format1.fontCapitalization()); + QCOMPARE(f.fontKerning(), format1.fontKerning()); + + QCOMPARE((int)f.font().styleHint(), (int)f.fontStyleHint()); + QCOMPARE((int)f.font().styleStrategy(), (int)f.fontStyleStrategy()); + QCOMPARE((int)f.font().capitalization(), (int)f.fontCapitalization()); + QCOMPARE(f.font().kerning(), f.fontKerning()); + + { + QTextCharFormat tmp; + tmp.setFont(font2, overrideAll ? QTextCharFormat::FontPropertiesAll + : QTextCharFormat::FontPropertiesSpecifiedOnly); + f.merge(tmp); + } + QCOMPARE((int)f.font().styleHint(), (int)f.fontStyleHint()); + QCOMPARE((int)f.font().styleStrategy(), (int)f.fontStyleStrategy()); + QCOMPARE((int)f.font().capitalization(), (int)f.fontCapitalization()); + QCOMPARE(f.font().kerning(), f.fontKerning()); + + if (overrideAll || (font2.resolve() & QFont::StyleHintResolved)) + QCOMPARE((int)f.font().styleHint(), (int)font2.styleHint()); + else + QCOMPARE((int)f.font().styleHint(), (int)font1.styleHint()); + if (overrideAll || (font2.resolve() & QFont::StyleStrategyResolved)) + QCOMPARE((int)f.font().styleStrategy(), (int)font2.styleStrategy()); + else + QCOMPARE((int)f.font().styleStrategy(), (int)font1.styleStrategy()); + if (overrideAll || (font2.resolve() & QFont::CapitalizationResolved)) + QCOMPARE((int)f.font().capitalization(), (int)font2.capitalization()); + else + QCOMPARE((int)f.font().capitalization(), (int)font1.capitalization()); + if (overrideAll || (font2.resolve() & QFont::KerningResolved)) + QCOMPARE(f.font().kerning(), font2.kerning()); + else + QCOMPARE(f.font().kerning(), font1.kerning()); +} + +void tst_QTextFormat::setFont_collection_data() +{ + setFont_data(); +} + +void tst_QTextFormat::setFont_collection() +{ + QFETCH(QTextCharFormat, format1); + QFETCH(QTextCharFormat, format2); + QFETCH(bool, overrideAll); + + QFont font1 = format1.font(); + QFont font2 = format2.font(); + + { + QTextFormatCollection collection; + collection.setDefaultFont(font1); + + int formatIndex = collection.indexForFormat(format1); + QTextCharFormat f = collection.charFormat(formatIndex); + + QCOMPARE((int)f.fontStyleHint(), (int)format1.fontStyleHint()); + QCOMPARE((int)f.fontStyleStrategy(), (int)format1.fontStyleStrategy()); + QCOMPARE((int)f.fontCapitalization(), (int)format1.fontCapitalization()); + QCOMPARE(f.fontKerning(), format1.fontKerning()); + + QCOMPARE((int)f.font().styleHint(), (int)f.fontStyleHint()); + QCOMPARE((int)f.font().styleStrategy(), (int)f.fontStyleStrategy()); + QCOMPARE((int)f.font().capitalization(), (int)f.fontCapitalization()); + QCOMPARE(f.font().kerning(), f.fontKerning()); + } + { + QTextFormatCollection collection; + collection.setDefaultFont(font1); + + int formatIndex = collection.indexForFormat(format2); + QTextCharFormat f = collection.charFormat(formatIndex); + + if (format2.hasProperty(QTextFormat::FontStyleHint)) + QCOMPARE((int)f.font().styleHint(), (int)format2.fontStyleHint()); + else + QCOMPARE((int)f.font().styleHint(), (int)format1.fontStyleHint()); + if (format2.hasProperty(QTextFormat::FontStyleStrategy)) + QCOMPARE((int)f.font().styleStrategy(), (int)format2.fontStyleStrategy()); + else + QCOMPARE((int)f.font().styleStrategy(), (int)format1.fontStyleStrategy()); + if (format2.hasProperty(QTextFormat::FontCapitalization)) + QCOMPARE((int)f.font().capitalization(), (int)format2.fontCapitalization()); + else + QCOMPARE((int)f.font().capitalization(), (int)format1.fontCapitalization()); + if (format2.hasProperty(QTextFormat::FontKerning)) + QCOMPARE(f.font().kerning(), format2.fontKerning()); + else + QCOMPARE(f.font().kerning(), format1.fontKerning()); + } + + { + QTextFormatCollection collection; + collection.setDefaultFont(font1); + + QTextCharFormat tmp; + tmp.setFont(font1, overrideAll ? QTextCharFormat::FontPropertiesAll + : QTextCharFormat::FontPropertiesSpecifiedOnly); + int formatIndex = collection.indexForFormat(tmp); + QTextCharFormat f = collection.charFormat(formatIndex); + + QCOMPARE((int)f.fontStyleHint(), (int)format1.fontStyleHint()); + QCOMPARE((int)f.fontStyleStrategy(), (int)format1.fontStyleStrategy()); + QCOMPARE((int)f.fontCapitalization(), (int)format1.fontCapitalization()); + QCOMPARE(f.fontKerning(), format1.fontKerning()); + + QCOMPARE((int)f.font().styleHint(), (int)f.fontStyleHint()); + QCOMPARE((int)f.font().styleStrategy(), (int)f.fontStyleStrategy()); + QCOMPARE((int)f.font().capitalization(), (int)f.fontCapitalization()); + QCOMPARE(f.font().kerning(), f.fontKerning()); + } + { + QTextFormatCollection collection; + collection.setDefaultFont(font1); + + QTextCharFormat tmp; + tmp.setFont(font2, overrideAll ? QTextCharFormat::FontPropertiesAll + : QTextCharFormat::FontPropertiesSpecifiedOnly); + int formatIndex = collection.indexForFormat(tmp); + QTextCharFormat f = collection.charFormat(formatIndex); + + if (overrideAll || (font2.resolve() & QFont::StyleHintResolved)) + QCOMPARE((int)f.font().styleHint(), (int)font2.styleHint()); + else + QCOMPARE((int)f.font().styleHint(), (int)font1.styleHint()); + if (overrideAll || (font2.resolve() & QFont::StyleStrategyResolved)) + QCOMPARE((int)f.font().styleStrategy(), (int)font2.styleStrategy()); + else + QCOMPARE((int)f.font().styleStrategy(), (int)font1.styleStrategy()); + if (overrideAll || (font2.resolve() & QFont::CapitalizationResolved)) + QCOMPARE((int)f.font().capitalization(), (int)font2.capitalization()); + else + QCOMPARE((int)f.font().capitalization(), (int)font1.capitalization()); + if (overrideAll || (font2.resolve() & QFont::KerningResolved)) + QCOMPARE(f.font().kerning(), font2.kerning()); + else + QCOMPARE(f.font().kerning(), font1.kerning()); + } +} + QTEST_MAIN(tst_QTextFormat) #include "tst_qtextformat.moc"