summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2021-08-18 11:47:16 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-08-19 14:24:04 +0000
commit6a2b565b5bed2616a4f5b7a14931e09594f4670b (patch)
treecdc806fdd3d4de14f2cacf497ec57a873403674c
parenteb14ce098cbf2296f4f5a7db38aca12eb2f325f3 (diff)
Fix bug with NoFontMerging when font does not support script
When using NoFontMerging, no fallbacks should be resolved. If the font does not support a specific character in the text, we should display a box instead of merging it with another font. But in practice, Qt would still apply the fallback mechanism for one specific case: If the font itself does not support the script of the text, we would get no match and do a search for a fallback instead. Since NoFontMerging is set, we would then force this as preresolved for *all* scripts in the QFont's private data (logically, the match should only have a single response for NoFontMerging). The end result was that if you set the font family before updating the text, you would get broken rendering. This can happen e.g. in Qt Quick, where you could update the font family of a text label while it contains characters which are not supported by the new font. Qt would then pick a fallback instead. When you subsequently update the text, the fallback would already be preresolved for whatever script this is. If it does not support the updated text, we would then see boxes, even if the requested font actually would have supported it. The fix is simply to do an additional pass if NoFontMerging is set and we were not able to match with the specified script. Since the same family might be available in different foundries, with different writing system support, we still want to do a pass first to see if we can match the exact script of the text. Note that QRawFont::fromFont() exploited the bug by using NoFontMerging for getting the fallback font for a specific writing system. To keep this working without having to rewrite fromFont() and risk introducing regressions, we add an argument to make the findFont() function behave as before. It isn't super-pretty, but since it is private API it is hopefully fine. [ChangeLog][QtGui][Text] Fixed an issue with NoFontMerging and changing font families dynamically, where boxes would be seen in place of the correct text. Done-with: Andy Shaw Fixes: QTBUG-81770 Change-Id: Ide9a36d7528a1040172c5864fa99e7a82eac4e83 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com> Reviewed-by: Lars Knoll <lars.knoll@qt.io> (cherry picked from commit 43a63901f4eb61ad8a29f4cc7a1700685f88ec35) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/gui/text/qfontdatabase.cpp12
-rw-r--r--src/gui/text/qfontdatabase_p.h4
-rw-r--r--src/gui/text/qrawfont.cpp2
-rw-r--r--tests/auto/gui/text/qrawfont/tst_qrawfont.cpp27
4 files changed, 39 insertions, 6 deletions
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index d9b8238d90..eb95468b37 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -2350,7 +2350,9 @@ bool QFontDatabase::removeAllApplicationFonts()
/*!
\internal
*/
-QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &request, int script)
+QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &request,
+ int script,
+ bool preferScriptOverFamily)
{
QMutexLocker locker(fontDatabaseMutex());
@@ -2397,6 +2399,14 @@ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &request, int script)
// We populated familiy aliases (e.g. localized families), so try again
index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
}
+
+ // If we do not find a match and NoFontMerging is set, use the requested font even if it does
+ // not support the script.
+ //
+ // (we do this at the end to prefer foundries that support the script if they exist)
+ if (index < 0 && !multi && !preferScriptOverFamily)
+ index = match(QChar::Script_Common, request, family_name, foundry_name, &desc, blackListed);
+
if (index >= 0) {
QFontDef fontDef = request;
// Don't pass empty family names to the platform font database, since it will then invoke its own matching
diff --git a/src/gui/text/qfontdatabase_p.h b/src/gui/text/qfontdatabase_p.h
index f7998153a1..bf7efc27ef 100644
--- a/src/gui/text/qfontdatabase_p.h
+++ b/src/gui/text/qfontdatabase_p.h
@@ -266,7 +266,9 @@ public:
static void createDatabase();
static void parseFontName(const QString &name, QString &foundry, QString &family);
static QString resolveFontFamilyAlias(const QString &family);
- static QFontEngine *findFont(const QFontDef &request, int script /* QChar::Script */);
+ static QFontEngine *findFont(const QFontDef &request,
+ int script /* QChar::Script */,
+ bool preferScriptOverFamily = false);
static void load(const QFontPrivate *d, int script /* QChar::Script */);
static QFontDatabasePrivate *ensureFontDatabase();
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index 00a2939e79..b538c22ee3 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -760,7 +760,7 @@ QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writ
QFontDef request(multiEngine->fontDef);
request.styleStrategy |= QFont::NoFontMerging;
- if (QFontEngine *engine = QFontDatabasePrivate::findFont(request, script)) {
+ if (QFontEngine *engine = QFontDatabasePrivate::findFont(request, script, true)) {
if (request.weight > QFont::Normal)
engine->fontDef.weight = request.weight;
if (request.style > QFont::StyleNormal)
diff --git a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp
index c324aa3549..a730174ee9 100644
--- a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp
+++ b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp
@@ -652,6 +652,7 @@ void tst_QRawFont::fromFont_data()
QTest::addColumn<QFont::HintingPreference>("hintingPreference");
QTest::addColumn<QString>("familyName");
QTest::addColumn<QFontDatabase::WritingSystem>("writingSystem");
+ QTest::addColumn<QFont::StyleStrategy>("styleStrategy");
for (int i=QFont::PreferDefaultHinting; i<=QFont::PreferFullHinting; ++i) {
QString titleBase = QString::fromLatin1("%2, hintingPreference=%1, writingSystem=%3")
@@ -665,7 +666,8 @@ void tst_QRawFont::fromFont_data()
<< fileName
<< QFont::HintingPreference(i)
<< "QtBidiTestFont"
- << writingSystem;
+ << writingSystem
+ << QFont::PreferDefault;
}
{
@@ -677,7 +679,8 @@ void tst_QRawFont::fromFont_data()
<< fileName
<< QFont::HintingPreference(i)
<< "QtBidiTestFont"
- << writingSystem;
+ << writingSystem
+ << QFont::PreferDefault;
}
{
@@ -689,9 +692,24 @@ void tst_QRawFont::fromFont_data()
<< fileName
<< QFont::HintingPreference(i)
<< "QtBidiTestFont"
- << writingSystem;
+ << writingSystem
+ << QFont::PreferDefault;
}
}
+
+ {
+ QString fileName = testFont;
+ QFontDatabase::WritingSystem writingSystem = QFontDatabase::Arabic;
+
+ QString title = QStringLiteral("No font merging + unsupported script");
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::PreferDefaultHinting
+ << "QtBidiTestFont"
+ << writingSystem
+ << QFont::NoFontMerging;
+ }
+
}
void tst_QRawFont::fromFont()
@@ -700,6 +718,7 @@ void tst_QRawFont::fromFont()
QFETCH(QFont::HintingPreference, hintingPreference);
QFETCH(QString, familyName);
QFETCH(QFontDatabase::WritingSystem, writingSystem);
+ QFETCH(QFont::StyleStrategy, styleStrategy);
int id = QFontDatabase::addApplicationFont(fileName);
QVERIFY(id >= 0);
@@ -707,6 +726,8 @@ void tst_QRawFont::fromFont()
QFont font(familyName);
font.setHintingPreference(hintingPreference);
font.setPixelSize(26.0);
+ if (styleStrategy != QFont::PreferDefault)
+ font.setStyleStrategy(styleStrategy);
QRawFont rawFont = QRawFont::fromFont(font, writingSystem);
QVERIFY(rawFont.isValid());