Fix distribution of font properties in QTextFormat

The area reserved for font properties was too small for
the properties we needed, and as a result font properties
were added outside of the area and special-cased (in the case
of FontLetterSpacingType) or ignored (in the case of
FontStretch) by conditions that check if the property is
within the designated area.

We reorganize the enum values now that we can, and allocate
some more space for the font properties area.

Fixes: QTBUG-65345
Change-Id: I8121ff7f72102d8022c6a6d2f8ed9c35dcdbb321
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2020-02-07 12:44:03 +01:00
parent 1ef8470c80
commit 761197e9d2
3 changed files with 166 additions and 12 deletions

View File

@ -201,10 +201,9 @@ public:
inline void insertProperty(qint32 key, const QVariant &value)
{
hashDirty = true;
if ((key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty)
|| key == QTextFormat::FontLetterSpacingType) {
if (key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty)
fontDirty = true;
}
for (int i = 0; i < props.count(); ++i)
if (props.at(i).key == key) {
props[i].value = value;
@ -218,10 +217,8 @@ public:
for (int i = 0; i < props.count(); ++i)
if (props.at(i).key == key) {
hashDirty = true;
if ((key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty)
|| key == QTextFormat::FontLetterSpacingType) {
if (key >= QTextFormat::FirstFontProperty && key <= QTextFormat::LastFontProperty)
fontDirty = true;
}
props.remove(i);
return;
}
@ -444,7 +441,22 @@ void QTextFormatPrivate::recalcFont() const
#ifndef QT_NO_DATASTREAM
Q_GUI_EXPORT QDataStream &operator<<(QDataStream &stream, const QTextFormat &fmt)
{
stream << fmt.format_type << fmt.properties();
QMap<int, QVariant> properties = fmt.properties();
if (stream.version() < QDataStream::Qt_6_0) {
auto it = properties.find(QTextFormat::FontLetterSpacingType);
if (it != properties.end()) {
properties[QTextFormat::OldFontLetterSpacingType] = it.value();
properties.erase(it);
}
it = properties.find(QTextFormat::FontStretch);
if (it != properties.end()) {
properties[QTextFormat::OldFontStretch] = it.value();
properties.erase(it);
}
}
stream << fmt.format_type << properties;
return stream;
}
@ -459,8 +471,14 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
fmt.d = new QTextFormatPrivate();
for (QMap<qint32, QVariant>::ConstIterator it = properties.constBegin();
it != properties.constEnd(); ++it)
fmt.d->insertProperty(it.key(), it.value());
it != properties.constEnd(); ++it) {
qint32 key = it.key();
if (key == QTextFormat::OldFontLetterSpacingType)
key = QTextFormat::FontLetterSpacingType;
else if (key == QTextFormat::OldFontStretch)
key = QTextFormat::FontStretch;
fmt.d->insertProperty(key, it.value());
}
return stream;
}
@ -620,6 +638,8 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
\value IsAnchor
\value AnchorHref
\value AnchorName
\omitvalue OldFontLetterSpacingType
\omitvalue OldFontStretch
\value ObjectType
List properties

View File

@ -184,16 +184,16 @@ public:
// character properties
FirstFontProperty = 0x1FE0,
FontCapitalization = FirstFontProperty,
FontLetterSpacingType = 0x2033,
FontLetterSpacing = 0x1FE1,
FontWordSpacing = 0x1FE2,
FontStretch = 0x2034,
FontStyleHint = 0x1FE3,
FontStyleStrategy = 0x1FE4,
FontKerning = 0x1FE5,
FontHintingPreference = 0x1FE6,
FontFamilies = 0x1FE7,
FontStyleName = 0x1FE8,
FontLetterSpacingType = 0x1FE9,
FontStretch = 0x1FEA,
FontFamily = 0x2000,
FontPointSize = 0x2001,
FontSizeAdjustment = 0x2002,
@ -207,7 +207,7 @@ public:
FontPixelSize = 0x2009,
LastFontProperty = FontPixelSize,
TextUnderlineColor = 0x2010,
TextUnderlineColor = 0x2020,
TextVerticalAlignment = 0x2021,
TextOutline = 0x2022,
TextUnderlineStyle = 0x2023,
@ -216,6 +216,12 @@ public:
IsAnchor = 0x2030,
AnchorHref = 0x2031,
AnchorName = 0x2032,
// Included for backwards compatibility with old QDataStreams.
// Should not be referenced in user code.
OldFontLetterSpacingType = 0x2033,
OldFontStretch = 0x2034,
ObjectType = 0x2f00,
// list properties

View File

@ -40,6 +40,10 @@
#include <qtextlayout.h>
#include <qabstracttextdocumentlayout.h>
#ifndef QT_NO_DATASTREAM
# include <qdatastream.h>
#endif
class tst_QTextFormat : public QObject
{
Q_OBJECT
@ -61,6 +65,10 @@ private slots:
void setFont_collection_data();
void setFont_collection();
void clearCollection();
#ifndef QT_NO_DATASTREAM
void dataStreamCompatibility();
#endif
};
/*! \internal
@ -677,5 +685,125 @@ void tst_QTextFormat::clearCollection()
QCOMPARE(collection.defaultFont(), f); // kept, QTextDocument::clear or setPlainText should not reset the font set by setDefaultFont
}
#ifndef QT_NO_DATASTREAM
void tst_QTextFormat::dataStreamCompatibility()
{
// Make sure that we are still compatible with the old values of QTextFormat::FontLetterSpacingType
// and QTextFormat::FontStretch, when used with earlier QDataStream versions
QTextCharFormat format;
format.setFontStretch(42);
format.setFontLetterSpacingType(QFont::AbsoluteSpacing);
// Sanity check
{
QMap<int, QVariant> properties = format.properties();
QVERIFY(properties.contains(QTextFormat::FontLetterSpacingType));
QVERIFY(properties.contains(QTextFormat::FontStretch));
QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType));
QVERIFY(!properties.contains(QTextFormat::OldFontStretch));
}
QByteArray memory;
// Current stream version
{
{
QBuffer buffer(&memory);
buffer.open(QIODevice::WriteOnly);
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::FontLetterSpacingType));
QVERIFY(properties.contains(QTextFormat::FontStretch));
QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType));
QVERIFY(!properties.contains(QTextFormat::OldFontStretch));
}
}
{
QBuffer buffer(&memory);
buffer.open(QIODevice::ReadOnly);
QDataStream stream(&buffer);
quint32 type;
stream >> type;
QMap<qint32, QVariant> properties;
stream >> properties;
QVERIFY(properties.contains(QTextFormat::FontLetterSpacingType));
QVERIFY(properties.contains(QTextFormat::FontStretch));
QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType));
QVERIFY(!properties.contains(QTextFormat::OldFontStretch));
}
}
// Qt 5.15 stream version
memory.clear();
{
{
QBuffer buffer(&memory);
buffer.open(QIODevice::WriteOnly);
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::FontLetterSpacingType));
QVERIFY(properties.contains(QTextFormat::FontStretch));
QVERIFY(!properties.contains(QTextFormat::OldFontLetterSpacingType));
QVERIFY(!properties.contains(QTextFormat::OldFontStretch));
}
}
{
QBuffer buffer(&memory);
buffer.open(QIODevice::ReadOnly);
QDataStream stream(&buffer);
stream.setVersion(QDataStream::Qt_5_15);
quint32 type;
stream >> type;
// Verify that old data stream still has the compatibility values
QMap<qint32, QVariant> properties;
stream >> properties;
QVERIFY(!properties.contains(QTextFormat::FontLetterSpacingType));
QVERIFY(!properties.contains(QTextFormat::FontStretch));
QVERIFY(properties.contains(QTextFormat::OldFontLetterSpacingType));
QVERIFY(properties.contains(QTextFormat::OldFontStretch));
}
}
}
#endif // QT_NO_DATASTREAM
QTEST_MAIN(tst_QTextFormat)
#include "tst_qtextformat.moc"