diff options
Diffstat (limited to 'src/gui/text/qfontdatabase.cpp')
-rw-r--r-- | src/gui/text/qfontdatabase.cpp | 208 |
1 files changed, 179 insertions, 29 deletions
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index a4aa8bf356..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(); @@ -254,13 +259,13 @@ bool QtFontFamily::matchesFamilyName(const QString &familyName) const return equalsCaseInsensitive(name, familyName) || aliases.contains(familyName, Qt::CaseInsensitive); } -void QtFontFamily::ensurePopulated() +bool QtFontFamily::ensurePopulated() { if (populated) - return; + return true; QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamily(name); - Q_ASSERT_X(populated, Q_FUNC_INFO, qPrintable(name)); + return populated; } void QFontDatabasePrivate::clearFamilies() @@ -280,6 +285,8 @@ void QFontDatabasePrivate::clearFamilies() void QFontDatabasePrivate::invalidate() { + qCDebug(lcFontDb) << "Invalidating font database"; + QFontCache::instance()->clear(); fallbacksCache.clear(); @@ -329,8 +336,10 @@ QtFontFamily *QFontDatabasePrivate::family(const QString &f, FamilyRequestFlags fam = families[pos]; } - if (fam && (flags & EnsurePopulated)) - fam->ensurePopulated(); + if (fam && (flags & EnsurePopulated)) { + if (!fam->ensurePopulated()) + return nullptr; + } return fam; } @@ -435,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(); @@ -444,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(); @@ -562,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); } @@ -571,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) @@ -657,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) { @@ -720,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; } @@ -745,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; @@ -772,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)); @@ -1047,7 +1061,8 @@ int QFontDatabasePrivate::match(int script, const QFontDef &request, const QStri if (!matchFamilyName(family_name, test.family)) continue; - test.family->ensurePopulated(); + if (!test.family->ensurePopulated()) + continue; // Check if family is supported in the script we want if (writingSystem != QFontDatabase::Any && !familySupportsWritingSystem(test.family, writingSystem)) @@ -1187,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 */ /*! @@ -1313,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"); @@ -1320,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); @@ -1351,7 +1367,8 @@ QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() for (int i = 0; i < d->count; ++i) { QtFontFamily *family = d->families[i]; - family->ensurePopulated(); + if (!family->ensurePopulated()) + continue; if (family->count == 0) continue; @@ -1423,7 +1440,8 @@ QStringList QFontDatabase::families(WritingSystem writingSystem) if (f->populated && f->count == 0) continue; if (writingSystem != Any) { - f->ensurePopulated(); + if (!f->ensurePopulated()) + continue; if (f->writingSystems[writingSystem] != QtFontFamily::Supported) continue; } @@ -1571,8 +1589,8 @@ bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &sty for (int i = 0; i < d->count; i++) { if (d->families[i]->matchesFamilyName(familyName)) { f = d->families[i]; - f->ensurePopulated(); - break; + if (f->ensurePopulated()) + break; } } } @@ -1892,7 +1910,19 @@ bool QFontDatabase::hasFamily(const QString &family) QString parsedFamily, foundry; parseFontName(family, foundry, parsedFamily); const QString familyAlias = QFontDatabasePrivate::resolveFontFamilyAlias(parsedFamily); - return families().contains(familyAlias, Qt::CaseInsensitive); + + QMutexLocker locker(fontDatabaseMutex()); + QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase(); + + for (int i = 0; i < d->count; i++) { + QtFontFamily *f = d->families[i]; + if (f->populated && f->count == 0) + continue; + if (familyAlias.compare(f->name, Qt::CaseInsensitive) == 0) + return true; + } + + return false; } @@ -2135,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()) @@ -2164,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; @@ -2296,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(); @@ -2331,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, @@ -2436,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()) @@ -2498,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()) @@ -2512,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)) @@ -2580,8 +2730,8 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script for (int x = 0; x < db->count; ++x) { if (Q_UNLIKELY(matchFamilyName(family, db->families[x]))) { testFamily = db->families[x]; - testFamily->ensurePopulated(); - break; + if (testFamily->ensurePopulated()) + break; } } |