Properly serialize QFont.

Some data was never serialized (styleName, hintingPreference) and
some was incorrectly serialized (styleStrategy). This change also adds
auto tests for every applicable QDataStream version.

[ChangeLog][QtGui][QFont] QFont now serializes its data properly,
without any data loss.

Task-number: QTBUG-22814
Task-number: QTBUG-22946

Change-Id: I34e61b10662b7ad6c57054dacc7e1f522f5b5c5d
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
This commit is contained in:
Mitch Curtis 2014-03-26 11:06:31 +01:00 committed by The Qt Project
parent bd822bedfe
commit 4f50be8d18
5 changed files with 140 additions and 27 deletions

View File

@ -89,7 +89,7 @@ public:
Qt_5_1 = 14,
Qt_5_2 = 15,
Qt_5_3 = Qt_5_2,
Qt_5_4 = Qt_5_3
Qt_5_4 = 16
#if QT_VERSION >= 0x050500
#error Add the datastream version for this Qt version
#endif

View File

@ -2163,6 +2163,8 @@ QDataStream &operator<<(QDataStream &s, const QFont &font)
s << font.d->request.family.toLatin1();
} else {
s << font.d->request.family;
if (s.version() >= QDataStream::Qt_5_4)
s << font.d->request.styleName;
}
if (s.version() >= QDataStream::Qt_4_0) {
@ -2183,8 +2185,14 @@ QDataStream &operator<<(QDataStream &s, const QFont &font)
}
s << (quint8) font.d->request.styleHint;
if (s.version() >= QDataStream::Qt_3_1)
s << (quint8) font.d->request.styleStrategy;
if (s.version() >= QDataStream::Qt_3_1) {
// Continue writing 8 bits for versions < 5.4 so that we don't write too much,
// even though we need 16 to store styleStrategy, so there is some data loss.
if (s.version() >= QDataStream::Qt_5_4)
s << (quint16) font.d->request.styleStrategy;
else
s << (quint8) font.d->request.styleStrategy;
}
s << (quint8) 0
<< (quint8) font.d->request.weight
<< get_font_bits(s.version(), font.d.data());
@ -2196,6 +2204,8 @@ QDataStream &operator<<(QDataStream &s, const QFont &font)
s << font.d->letterSpacing.value();
s << font.d->wordSpacing.value();
}
if (s.version() >= QDataStream::Qt_5_4)
s << (quint8)font.d->request.hintingPreference;
return s;
}
@ -2213,7 +2223,8 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
font.d = new QFontPrivate;
font.resolve_mask = QFont::AllPropertiesResolved;
quint8 styleHint, styleStrategy = QFont::PreferDefault, charSet, weight, bits;
quint8 styleHint, charSet, weight, bits;
quint16 styleStrategy = QFont::PreferDefault;
if (s.version() == 1) {
QByteArray fam;
@ -2221,6 +2232,8 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
font.d->request.family = QString::fromLatin1(fam);
} else {
s >> font.d->request.family;
if (s.version() >= QDataStream::Qt_5_4)
s >> font.d->request.styleName;
}
if (s.version() >= QDataStream::Qt_4_0) {
@ -2240,8 +2253,15 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
font.d->request.pixelSize = pixelSize;
}
s >> styleHint;
if (s.version() >= QDataStream::Qt_3_1)
s >> styleStrategy;
if (s.version() >= QDataStream::Qt_3_1) {
if (s.version() >= QDataStream::Qt_5_4) {
s >> styleStrategy;
} else {
quint8 tempStyleStrategy;
s >> tempStyleStrategy;
styleStrategy = tempStyleStrategy;
}
}
s >> charSet;
s >> weight;
@ -2271,6 +2291,11 @@ QDataStream &operator>>(QDataStream &s, QFont &font)
s >> value;
font.d->wordSpacing.setValue(value);
}
if (s.version() >= QDataStream::Qt_5_4) {
quint8 value;
s >> value;
font.d->request.hintingPreference = QFont::HintingPreference(value);
}
return s;
}

View File

@ -92,7 +92,7 @@ struct QFontDef
uint weight : 7; // 0-99
uint fixedPitch : 1;
uint style : 2;
uint stretch : 12; // 0-400
uint stretch : 12; // 0-4000
uint hintingPreference : 2;
uint ignorePitch : 1;

View File

@ -270,7 +270,9 @@ static int NColorRoles[] = {
QPalette::ToolTipText + 1, // Qt_5_0
QPalette::ToolTipText + 1, // Qt_5_1
QPalette::ToolTipText + 1, // Qt_5_2
0 // add the correct value for Qt_5_3 here later
QPalette::ToolTipText + 1, // Qt_5_3
QPalette::ToolTipText + 1, // Qt_5_4
0 // add the correct value for Qt_5_5 here later
};
// Testing get/set functions

View File

@ -77,7 +77,8 @@ private slots:
void setFontRaw();
void italicOblique();
void insertAndRemoveSubstitutions();
void serializeSpacing();
void serialize_data();
void serialize();
void lastResortFont();
void styleName();
void defaultFamily_data();
@ -568,7 +569,6 @@ void tst_QFont::insertAndRemoveSubstitutions()
QVERIFY(QFont::substitutes("bogusfontfamily").isEmpty());
}
static QFont copyFont(const QFont &font1) // copy using a QDataStream
{
QBuffer buffer;
@ -583,29 +583,115 @@ static QFont copyFont(const QFont &font1) // copy using a QDataStream
return font2;
}
void tst_QFont::serializeSpacing()
Q_DECLARE_METATYPE(QDataStream::Version)
void tst_QFont::serialize_data()
{
QFont font;
QCOMPARE(font.letterSpacing(), 0.);
QCOMPARE(font.wordSpacing(), 0.);
QTest::addColumn<QFont>("font");
// The version in which the tested feature was added.
QTest::addColumn<QDataStream::Version>("minimumStreamVersion");
QFont basicFont;
// Versions <= Qt 2.1 had broken point size serialization,
// so we set an integer point size.
basicFont.setPointSize(9);
QFont font = basicFont;
QTest::newRow("defaultConstructed") << font << QDataStream::Qt_1_0;
font.setLetterSpacing(QFont::AbsoluteSpacing, 105);
QCOMPARE(font.letterSpacing(), 105.);
QCOMPARE(font.letterSpacingType(), QFont::AbsoluteSpacing);
QCOMPARE(font.wordSpacing(), 0.);
QFont font2 = copyFont(font);
QCOMPARE(font2.letterSpacing(), 105.);
QCOMPARE(font2.letterSpacingType(), QFont::AbsoluteSpacing);
QCOMPARE(font2.wordSpacing(), 0.);
QTest::newRow("letterSpacing") << font << QDataStream::Qt_4_5;
font = basicFont;
font.setWordSpacing(50.0);
QCOMPARE(font.letterSpacing(), 105.);
QCOMPARE(font.wordSpacing(), 50.);
QTest::newRow("wordSpacing") << font << QDataStream::Qt_4_5;
QFont font3 = copyFont(font);
QCOMPARE(font3.letterSpacing(), 105.);
QCOMPARE(font3.letterSpacingType(), QFont::AbsoluteSpacing);
QCOMPARE(font3.wordSpacing(), 50.);
font = basicFont;
font.setPointSize(20);
QTest::newRow("pointSize") << font << QDataStream::Qt_1_0;
font = basicFont;
font.setPixelSize(32);
QTest::newRow("pixelSize") << font << QDataStream::Qt_3_0;
font = basicFont;
font.setStyleHint(QFont::Monospace);
QTest::newRow("styleHint") << font << QDataStream::Qt_1_0;
font = basicFont;
font.setStretch(4000);
QTest::newRow("stretch") << font << QDataStream::Qt_4_3;
font = basicFont;
font.setWeight(99);
QTest::newRow("weight") << font << QDataStream::Qt_1_0;
font = basicFont;
font.setUnderline(true);
QTest::newRow("underline") << font << QDataStream::Qt_1_0;
font = basicFont;
font.setStrikeOut(true);
QTest::newRow("strikeOut") << font << QDataStream::Qt_1_0;
font = basicFont;
font.setFixedPitch(true);
// This fails for versions less than this, as ignorePitch is set to false
// whenever setFixedPitch() is called, but ignorePitch is considered an
// extended bit, which were apparently not available until 4.4.
QTest::newRow("fixedPitch") << font << QDataStream::Qt_4_4;
font = basicFont;
font.setLetterSpacing(QFont::AbsoluteSpacing, 10);
// Fails for 4.4 because letterSpacing wasn't read until 4.5.
QTest::newRow("letterSpacing") << font << QDataStream::Qt_4_5;
font = basicFont;
font.setRawMode(true);
QTest::newRow("rawMode") << font << QDataStream::Qt_1_0;
font = basicFont;
font.setKerning(false);
QTest::newRow("kerning") << font << QDataStream::Qt_4_0;
font = basicFont;
font.setStyleStrategy(QFont::NoFontMerging);
// This wasn't read properly until 5.4.
QTest::newRow("styleStrategy") << font << QDataStream::Qt_5_4;
font = basicFont;
font.setHintingPreference(QFont::PreferFullHinting);
// This wasn't read until 5.4.
QTest::newRow("hintingPreference") << font << QDataStream::Qt_5_4;
font = basicFont;
font.setStyleName("Regular Black Condensed");
// This wasn't read until 5.4.
QTest::newRow("styleName") << font << QDataStream::Qt_5_4;
}
void tst_QFont::serialize()
{
QFETCH(QFont, font);
QFETCH(QDataStream::Version, minimumStreamVersion);
QDataStream stream;
const int thisVersion = stream.version();
for (int version = minimumStreamVersion; version <= thisVersion; ++version) {
QBuffer buffer;
buffer.open(QIODevice::WriteOnly);
stream.setDevice(&buffer);
stream.setVersion(version);
stream << font;
buffer.close();
buffer.open(QIODevice::ReadOnly);
QFont readFont;
stream >> readFont;
QVERIFY2(readFont == font, qPrintable(QString::fromLatin1("Fonts do not compare equal for QDataStream version ") +
QString::fromLatin1("%1:\nactual: %2\nexpected: %3").arg(version).arg(readFont.toString()).arg(font.toString())));
}
}
// QFont::lastResortFont() may abort with qFatal() on QWS/QPA