diff options
Diffstat (limited to 'src/gui/text/qfontdatabase.cpp')
-rw-r--r-- | src/gui/text/qfontdatabase.cpp | 165 |
1 files changed, 149 insertions, 16 deletions
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index f2d2a2401d..d3a13d801b 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -48,6 +48,11 @@ Q_AUTOTEST_EXPORT void qt_setQtEnableTestFont(bool value) } #endif +Q_TRACE_POINT(qtgui, QFontDatabase_loadEngine, const QString &families, int pointSize); +Q_TRACE_POINT(qtgui, QFontDatabasePrivate_addAppFont, const QString &fileName); +Q_TRACE_POINT(qtgui, QFontDatabase_addApplicationFont, const QString &fileName); +Q_TRACE_POINT(qtgui, QFontDatabase_load, const QString &family, int pointSize); + static int getFontWeight(const QString &weightString) { QString s = weightString.toLower(); @@ -280,6 +285,8 @@ void QFontDatabasePrivate::clearFamilies() void QFontDatabasePrivate::invalidate() { + qCDebug(lcFontDb) << "Invalidating font database"; + QFontCache::instance()->clear(); fallbacksCache.clear(); @@ -437,7 +444,7 @@ static void parseFontName(const QString &name, QString &foundry, QString &family // capitalize the family/foundry names bool space = true; QChar *s = family.data(); - int len = family.length(); + int len = family.size(); while(len--) { if (space) *s = s->toUpper(); space = s->isSpace(); @@ -446,7 +453,7 @@ static void parseFontName(const QString &name, QString &foundry, QString &family space = true; s = foundry.data(); - len = foundry.length(); + len = foundry.size(); while(len--) { if (space) *s = s->toUpper(); space = s->isSpace(); @@ -564,6 +571,8 @@ void qt_registerFont(const QString &familyName, const QString &stylename, void qt_registerFontFamily(const QString &familyName) { + qCDebug(lcFontDb) << "Registering family" << familyName; + // Create uninitialized/unpopulated family QFontDatabasePrivate::instance()->family(familyName, QFontDatabasePrivate::EnsureCreated); } @@ -573,6 +582,8 @@ void qt_registerAliasToFontFamily(const QString &familyName, const QString &alia if (alias.isEmpty()) return; + qCDebug(lcFontDb) << "Registering alias" << alias << "to family" << familyName; + auto *d = QFontDatabasePrivate::instance(); QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily); if (!f) @@ -659,7 +670,8 @@ static QStringList fallbacksForFamily(const QString &family, QFont::Style style, return *fallbacks; // make sure that the db has all fallback families - QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script); + QStringList userFallbacks = db->applicationFallbackFontFamilies.value(script == QChar::Script_Common ? QChar::Script_Latin : script); + QStringList retList = userFallbacks + QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script); QStringList::iterator i; for (i = retList.begin(); i != retList.end(); ++i) { @@ -722,7 +734,7 @@ QFontEngine *QFontDatabasePrivate::loadSingleEngine(int script, // Also check for OpenType tables when using complex scripts if (Q_UNLIKELY(!engine->supportsScript(QChar::Script(script)))) { qWarning(" OpenType support missing for \"%s\", script %d", - qPrintable(def.families.first()), script); + qPrintable(def.families.constFirst()), script); return nullptr; } @@ -747,7 +759,7 @@ QFontEngine *QFontDatabasePrivate::loadSingleEngine(int script, // Also check for OpenType tables when using complex scripts if (!engine->supportsScript(QChar::Script(script))) { qWarning(" OpenType support missing for \"%s\", script %d", - +qPrintable(def.families.first()), script); + +qPrintable(def.families.constFirst()), script); if (engine->ref.loadRelaxed() == 0) delete engine; return nullptr; @@ -774,7 +786,7 @@ QFontEngine *QFontDatabasePrivate::loadEngine(int script, const QFontDef &reques QFontEngine *engine = loadSingleEngine(script, request, family, foundry, style, size); if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) { - Q_TRACE(QFontDatabase_loadEngine, request.families, request.pointSize); + Q_TRACE(QFontDatabase_loadEngine, request.families.join(QLatin1Char(';')), request.pointSize); QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script)); @@ -1190,7 +1202,7 @@ QString QFontDatabase::styleString(const QFontInfo &fontInfo) each combination of family and style, displaying this information in a tree view. - \sa QFont, QFontInfo, QFontMetrics, {Character Map Example} + \sa QFont, QFontInfo, QFontMetrics */ /*! @@ -1316,6 +1328,7 @@ QFontDatabasePrivate *QFontDatabasePrivate::ensureFontDatabase() // The font database may have been partially populated, but to ensure // we can answer queries for any platform- or user-provided family we // need to fully populate it now. + qCDebug(lcFontDb) << "Populating font database"; if (Q_UNLIKELY(qGuiApp == nullptr || QGuiApplicationPrivate::platformIntegration() == nullptr)) qFatal("QFontDatabase: Must construct a QGuiApplication before accessing QFontDatabase"); @@ -1323,7 +1336,7 @@ QFontDatabasePrivate *QFontDatabasePrivate::ensureFontDatabase() auto *platformFontDatabase = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); platformFontDatabase->populateFontDatabase(); - for (int i = 0; i < d->applicationFonts.count(); i++) { + for (int i = 0; i < d->applicationFonts.size(); i++) { auto *font = &d->applicationFonts[i]; if (!font->isNull() && !font->isPopulated()) platformFontDatabase->addApplicationFont(font->data, font->fileName, font); @@ -2152,12 +2165,12 @@ int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString & Q_TRACE(QFontDatabasePrivate_addAppFont, fileName); int i; - for (i = 0; i < applicationFonts.count(); ++i) + for (i = 0; i < applicationFonts.size(); ++i) if (applicationFonts.at(i).isNull()) break; - if (i >= applicationFonts.count()) { + if (i >= applicationFonts.size()) { applicationFonts.append(ApplicationFont()); - i = applicationFonts.count() - 1; + i = applicationFonts.size() - 1; } if (font.fileName.isEmpty() && !fontData.isEmpty()) @@ -2181,7 +2194,7 @@ int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString & bool QFontDatabasePrivate::isApplicationFont(const QString &fileName) { - for (int i = 0; i < applicationFonts.count(); ++i) + for (int i = 0; i < applicationFonts.size(); ++i) if (applicationFonts.at(i).fileName == fileName) return true; return false; @@ -2313,7 +2326,7 @@ bool QFontDatabase::removeApplicationFont(int handle) QMutexLocker locker(fontDatabaseMutex()); auto *db = QFontDatabasePrivate::instance(); - if (handle < 0 || handle >= db->applicationFonts.count()) + if (handle < 0 || handle >= db->applicationFonts.size()) return false; db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont(); @@ -2348,6 +2361,126 @@ bool QFontDatabase::removeAllApplicationFonts() } /*! + \since 6.8 + + Adds \a familyName as an application-defined fallback font for \a script. + + When Qt encounters characters that are not supported by the selected font, it will search + through a list of fallback fonts to find a match for them. This ensures that combining multiple + scripts in a single string is possible, even if the main font does not support them. + + The list of fallback fonts is selected based on the script of the string as well as other + conditions, such as system language. + + While the system fallback list is usually sufficient, there are cases where it is useful + to override the default behavior. One such case is for using application fonts as fallback to + ensure cross-platform consistency. + + In another case the application may be written in a script with regional differences and want + to run it untranslated in multiple regions. In this case, it might be useful to override the + local region's fallback with one that matches the language of the application. + + By passing \a familyName to addApplicationFallbackFontFamily(), this will become the preferred + family when matching missing characters from \a script. The \a script must be a valid script + (\c QChar::Script_Latin or higher). When adding multiple fonts for the same script, they will + be prioritized in reverse order, so that the last family added will be checked first and so + on. + + \sa setApplicationFallbackFontFamilies(), removeApplicationFallbackFontFamily(), applicationFallbackFontFamilies() +*/ +void QFontDatabase::addApplicationFallbackFontFamily(QChar::Script script, const QString &familyName) +{ + QMutexLocker locker(fontDatabaseMutex()); + + if (script < QChar::Script_Latin) { + qCWarning(lcFontDb) << "Invalid script passed to addApplicationFallbackFontFamily:" << script; + return; + } + + auto *db = QFontDatabasePrivate::instance(); + auto it = db->applicationFallbackFontFamilies.find(script); + if (it == db->applicationFallbackFontFamilies.end()) + it = db->applicationFallbackFontFamilies.insert(script, QStringList{}); + + it->prepend(familyName); + db->fallbacksCache.clear(); +} + +/*! + \since 6.8 + + Removes \a familyName from the list of application-defined fallback fonts for \a script, + provided that it has previously been added with \l{addApplicationFallbackFontFamily()}. + + Returns true if the family name was in the list and false if it was not. + + \sa addApplicationFallbackFontFamily(), setApplicationFallbackFontFamilies(), applicationFallbackFontFamilies() +*/ +bool QFontDatabase::removeApplicationFallbackFontFamily(QChar::Script script, const QString &familyName) +{ + QMutexLocker locker(fontDatabaseMutex()); + + auto *db = QFontDatabasePrivate::instance(); + auto it = db->applicationFallbackFontFamilies.find(script); + if (it != db->applicationFallbackFontFamilies.end()) { + if (it->removeAll(familyName) > 0) { + if (it->isEmpty()) + it = db->applicationFallbackFontFamilies.erase(it); + QFontCache::instance()->clear(); + db->fallbacksCache.clear(); + return true; + } + } + + return false; +} + +/*! + \since 6.8 + + Sets the list of application-defined fallback fonts for \a script to \a familyNames. + + When Qt encounters a character in \a script which is not supported by the current font, it will + check the families in \a familyNames, in order from first to last, until it finds a match. See + \l{addApplicationFallbackFontFamily()} for more details. + + This function overwrites the current list of application-defined fallback fonts for \a script. + + \sa addApplicationFallbackFontFamily(), removeApplicationFallbackFontFamily(), applicationFallbackFontFamilies() +*/ +void QFontDatabase::setApplicationFallbackFontFamilies(QChar::Script script, const QStringList &familyNames) +{ + QMutexLocker locker(fontDatabaseMutex()); + + if (script < QChar::Script_Latin) { + qCWarning(lcFontDb) << "Invalid script passed to setApplicationFallbackFontFamilies:" << script; + return; + } + + auto *db = QFontDatabasePrivate::instance(); + db->applicationFallbackFontFamilies[script] = familyNames; + + QFontCache::instance()->clear(); + db->fallbacksCache.clear(); +} + +/*! + \since 6.8 + + Returns the list of application-defined fallback font families previously added for \a script + by the \l{addApplicationFallbackFontFamily()} function. + + \sa setApplicationFallbackFontFamilies(), addApplicationFallbackFontFamily(), removeApplicationFallbackFontFamily() +*/ +QStringList QFontDatabase::applicationFallbackFontFamilies(QChar::Script script) +{ + QMutexLocker locker(fontDatabaseMutex()); + + auto *db = QFontDatabasePrivate::instance(); + return db->applicationFallbackFontFamilies.value(script); +} + +/*! \internal */ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req, @@ -2453,7 +2586,7 @@ QFontEngine *QFontDatabasePrivate::findFont(const QFontDef &req, if (!engine) { QtFontDesc desc; do { - index = match(multi ? QChar::Script_Common : script, def, def.families.first(), ""_L1, &desc, blackListed); + index = match(multi ? QChar::Script_Common : script, def, def.families.constFirst(), ""_L1, &desc, blackListed); if (index >= 0) { QFontDef loadDef = def; if (loadDef.families.isEmpty()) @@ -2515,7 +2648,7 @@ void QFontDatabasePrivate::load(const QFontPrivate *d, int script) QFontEngine *fe = nullptr; - Q_TRACE(QFontDatabase_load, req.families, req.pointSize); + Q_TRACE(QFontDatabase_load, req.families.join(QLatin1Char(';')), req.pointSize); req.fallBackFamilies = fallBackFamilies; if (!req.fallBackFamilies.isEmpty()) @@ -2529,7 +2662,7 @@ void QFontDatabasePrivate::load(const QFontPrivate *d, int script) family_list << req.families.at(0); // add the default family - auto families = QGuiApplication::font().families(); + const auto families = QGuiApplication::font().families(); if (!families.isEmpty()) { QString defaultFamily = families.first(); if (! family_list.contains(defaultFamily)) |