Allow QTextCharFormat::setFont() to skip unresolved font props

This makes the font merging possible and solves an issue
with the default font properties inheritance when used
in conjunction with QTextFormatCollection.

Change-Id: If8b543c011122dde9f086f5d696df3b042f7b90c
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Konstantin Ritt 2014-01-17 17:38:55 +02:00 committed by The Qt Project
parent f6723cf0d4
commit f26928cccf
5 changed files with 332 additions and 52 deletions

View File

@ -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());
}
/*!

View File

@ -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)

View File

@ -1361,33 +1361,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
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);

View File

@ -1,5 +1,5 @@
CONFIG += testcase
CONFIG += parallel_test
TARGET = tst_qtextformat
QT += testlib
QT += testlib core-private gui-private
SOURCES += tst_qtextformat.cpp

View File

@ -46,6 +46,7 @@
#include <qdebug.h>
#include <qsettings.h>
#include <qtextformat.h>
#include <private/qtextformat_p.h>
#include <qtextdocument.h>
#include <qtextcursor.h>
#include <qtextobject.h>
@ -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<QTextCharFormat>("format1");
QTest::addColumn<QTextCharFormat>("format2");
QTest::addColumn<bool>("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"