From 12687ccfd5a6056ab24a792dbe28f1d5829fd88c Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 8 Jan 2018 13:29:38 +0100 Subject: [PATCH] CoreText: Order fallback fonts based on writing system support After we stopped sanitizing the fallback font list (with change 6ca48a847a1805c3826004c5b989b4ae14397a37), we now need to make sure it is ordered so that the fonts that support the writing system in question are always tested first, otherwise we can end up loading a lot of fonts that will never be used. Task-number: QTBUG-65605 Change-Id: Id2a65bbff3e64e6d6e6b4f72500778ee3e811e84 Reviewed-by: Konstantin Ritt --- src/gui/text/qfontdatabase.cpp | 35 +++++++++++++++++++ .../mac/qcoretextfontdatabase.mm | 3 ++ tests/auto/gui/text/qrawfont/tst_qrawfont.cpp | 35 +++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 2cc071d67b..33dc27983a 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -2837,6 +2837,41 @@ QString QFontDatabase::resolveFontFamilyAlias(const QString &family) return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family); } +Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script, const QStringList &families) +{ + size_t writingSystem = std::find(scriptForWritingSystem, + scriptForWritingSystem + QFontDatabase::WritingSystemsCount, + script) - scriptForWritingSystem; + if (writingSystem == QFontDatabase::Any + || writingSystem >= QFontDatabase::WritingSystemsCount) { + return families; + } + + QFontDatabasePrivate *db = privateDb(); + QMultiMap supported; + for (int i = 0; i < families.size(); ++i) { + const QString &family = families.at(i); + + QtFontFamily *testFamily = nullptr; + for (int x = 0; x < db->count; ++x) { + if (Q_UNLIKELY(matchFamilyName(family, db->families[x]))) { + testFamily = db->families[x]; + testFamily->ensurePopulated(); + break; + } + } + + uint order = i; + if (testFamily == nullptr + || (testFamily->writingSystems[writingSystem] & QtFontFamily::Supported) == 0) { + order |= 1 << 31; + } + + supported.insert(order, family); + } + + return supported.values(); +} QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 237e8a89a5..7397312820 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -544,6 +544,9 @@ QStringList QCoreTextFontDatabase::fallbacksForFamily(const QString &family, QFo fallbackList.append(QStringLiteral("Arial Unicode MS")); #endif + extern QStringList qt_sort_families_by_writing_system(QChar::Script, const QStringList &); + fallbackList = qt_sort_families_by_writing_system(script, fallbackList); + return fallbackList; } } diff --git a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp index ee775d4a31..37f94d0278 100644 --- a/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/gui/text/qrawfont/tst_qrawfont.cpp @@ -90,6 +90,9 @@ private slots: void rawFontFromInvalidData(); void kernedAdvances(); + + void fallbackFontsOrder(); + private: QString testFont; QString testFontBoldItalic; @@ -1009,6 +1012,38 @@ void tst_QRawFont::kernedAdvances() QVERIFY(FUZZY_LTEQ(qAbs(advances.at(0).x() - expectedAdvanceWidth), errorMargin)); } +void tst_QRawFont::fallbackFontsOrder() +{ + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(testFont); + + QFont font("QtBidiTestFont"); + font.setPixelSize(12.0); + + QString arabicText = QFontDatabase::writingSystemSample(QFontDatabase::Arabic); + + // If this fails, then the writing system sample has changed and we need to create + // a new text containing both a space and Arabic characters. + QVERIFY(arabicText.contains(QLatin1Char(' '))); + + QTextLayout layout; + layout.setFont(font); + layout.setText(arabicText); + layout.setCacheEnabled(true); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList glyphRuns = layout.glyphRuns(); + + // Since QtBidiTestFont does not support Arabic nor the space, both should map to + // the same font. If this fails, it is an indication that the list of fallbacks fonts + // is not sorted by writing system support. + QCOMPARE(glyphRuns.size(), 1); + + fontDatabase.removeApplicationFont(id); +} + #endif // QT_NO_RAWFONT QTEST_MAIN(tst_QRawFont)