summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qfontdatabase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/qfontdatabase.cpp')
-rw-r--r--src/gui/text/qfontdatabase.cpp914
1 files changed, 545 insertions, 369 deletions
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 2ec2263321..d3a13d801b 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfontdatabase.h"
#include "qfontdatabase_p.h"
@@ -62,8 +26,14 @@
#include <qtgui_tracepoints_p.h>
+#ifdef Q_OS_WIN
+#include <QtGui/private/qwindowsfontdatabasebase_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
Q_LOGGING_CATEGORY(lcFontDb, "qt.text.font.db")
Q_LOGGING_CATEGORY(lcFontMatch, "qt.text.font.match")
@@ -78,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();
@@ -90,41 +65,40 @@ static int getFontWeight(const QString &weightString)
//
// A simple string test is the cheapest, so let's do that first.
// Test in decreasing order of commonness
- if (s == QLatin1String("normal") || s == QLatin1String("regular"))
+ if (s == "normal"_L1 || s == "regular"_L1)
return QFont::Normal;
- if (s == QLatin1String("bold"))
+ if (s == "bold"_L1)
return QFont::Bold;
- if (s == QLatin1String("semibold") || s == QLatin1String("semi bold")
- || s == QLatin1String("demibold") || s == QLatin1String("demi bold"))
+ if (s == "semibold"_L1 || s == "semi bold"_L1 || s == "demibold"_L1 || s == "demi bold"_L1)
return QFont::DemiBold;
- if (s == QLatin1String("medium"))
+ if (s == "medium"_L1)
return QFont::Medium;
- if (s == QLatin1String("black"))
+ if (s == "black"_L1)
return QFont::Black;
- if (s == QLatin1String("light"))
+ if (s == "light"_L1)
return QFont::Light;
- if (s == QLatin1String("thin"))
+ if (s == "thin"_L1)
return QFont::Thin;
const QStringView s2 = QStringView{s}.mid(2);
- if (s.startsWith(QLatin1String("ex")) || s.startsWith(QLatin1String("ul"))) {
- if (s2 == QLatin1String("tralight") || s == QLatin1String("tra light"))
+ if (s.startsWith("ex"_L1) || s.startsWith("ul"_L1)) {
+ if (s2 == "tralight"_L1 || s == "tra light"_L1)
return QFont::ExtraLight;
- if (s2 == QLatin1String("trabold") || s2 == QLatin1String("tra bold"))
+ if (s2 == "trabold"_L1 || s2 == "tra bold"_L1)
return QFont::ExtraBold;
}
// Next up, let's see if contains() matches: slightly more expensive, but
// still fast enough.
- if (s.contains(QLatin1String("bold"))) {
- if (s.contains(QLatin1String("demi")))
+ if (s.contains("bold"_L1)) {
+ if (s.contains("demi"_L1))
return QFont::DemiBold;
return QFont::Bold;
}
- if (s.contains(QLatin1String("thin")))
+ if (s.contains("thin"_L1))
return QFont::Thin;
- if (s.contains(QLatin1String("light")))
+ if (s.contains("light"_L1))
return QFont::Light;
- if (s.contains(QLatin1String("black")))
+ if (s.contains("black"_L1))
return QFont::Black;
// Now, we perform string translations & comparisons with those.
@@ -181,9 +155,9 @@ QtFontStyle::Key::Key(const QString &styleString)
if (!styleString.isEmpty()) {
// First the straightforward no-translation checks, these are fast.
- if (styleString.contains(QLatin1String("Italic")))
+ if (styleString.contains("Italic"_L1))
style = QFont::StyleItalic;
- else if (styleString.contains(QLatin1String("Oblique")))
+ else if (styleString.contains("Oblique"_L1))
style = QFont::StyleOblique;
// Then the translation checks. These aren't as fast.
@@ -285,23 +259,40 @@ 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()
+{
+ while (count--)
+ delete families[count];
+ ::free(families);
+ families = nullptr;
+ count = 0;
+
+ for (auto &font : applicationFonts)
+ font.properties.clear(); // Unpopulate
+
+ populated = false;
+ // don't clear the memory fonts!
}
void QFontDatabasePrivate::invalidate()
{
+ qCDebug(lcFontDb) << "Invalidating font database";
+
QFontCache::instance()->clear();
fallbacksCache.clear();
- free();
+ clearFamilies();
QGuiApplicationPrivate::platformIntegration()->fontDatabase()->invalidate();
- emit static_cast<QGuiApplication *>(QCoreApplication::instance())->fontDatabaseChanged();
+ emit qGuiApp->fontDatabaseChanged();
}
QtFontFamily *QFontDatabasePrivate::family(const QString &f, FamilyRequestFlags flags)
@@ -345,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;
}
@@ -436,11 +429,11 @@ Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int scrip
*/
static void parseFontName(const QString &name, QString &foundry, QString &family)
{
- int i = name.indexOf(QLatin1Char('['));
- int li = name.lastIndexOf(QLatin1Char(']'));
+ int i = name.indexOf(u'[');
+ int li = name.lastIndexOf(u']');
if (i >= 0 && li >= 0 && i < li) {
foundry = name.mid(i + 1, li - i - 1);
- if (i > 0 && name[i - 1] == QLatin1Char(' '))
+ if (i > 0 && name[i - 1] == u' ')
i--;
family = name.left(i);
} else {
@@ -451,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();
@@ -460,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();
@@ -480,9 +473,11 @@ struct QtFontDesc
static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef, bool multi)
{
- fontDef->family = desc.family->name;
+ QString family;
+ family = desc.family->name;
if (! desc.foundry->name.isEmpty() && desc.family->count > 1)
- fontDef->family += QLatin1String(" [") + desc.foundry->name + QLatin1Char(']');
+ family += " ["_L1 + desc.foundry->name + u']';
+ fontDef->families = QStringList(family);
if (desc.style->smoothScalable
|| QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable()
@@ -510,19 +505,6 @@ static QStringList familyList(const QFontDef &req)
QStringList family_list;
family_list << req.families;
- if (!req.family.isEmpty()) {
- const auto list = QStringView{req.family}.split(QLatin1Char(','));
- const int numFamilies = list.size();
- family_list.reserve(numFamilies);
- for (int i = 0; i < numFamilies; ++i) {
- auto str = list.at(i).trimmed();
- if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"')))
- || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\''))))
- str = str.mid(1, str.length() - 2);
- if (!family_list.contains(str))
- family_list << str.toString();
- }
- }
// append the substitute list for each family in family_list
for (int i = 0, size = family_list.size(); i < size; ++i)
family_list += QFont::substitutes(family_list.at(i));
@@ -530,17 +512,14 @@ static QStringList familyList(const QFontDef &req)
return family_list;
}
-Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)
Q_GLOBAL_STATIC(QRecursiveMutex, fontDatabaseMutex)
// used in qguiapplication.cpp
void qt_cleanupFontDatabase()
{
- QFontDatabasePrivate *db = privateDb();
- if (db) {
- db->fallbacksCache.clear();
- db->free();
- }
+ auto *db = QFontDatabasePrivate::instance();
+ db->fallbacksCache.clear();
+ db->clearFamilies();
}
// used in qfont.cpp
@@ -551,7 +530,8 @@ QRecursiveMutex *qt_fontdatabase_mutex()
QFontDatabasePrivate *QFontDatabasePrivate::instance()
{
- return privateDb();
+ static QFontDatabasePrivate instance;
+ return &instance;
}
void qt_registerFont(const QString &familyName, const QString &stylename,
@@ -560,7 +540,7 @@ void qt_registerFont(const QString &familyName, const QString &stylename,
bool scalable, int pixelSize, bool fixedPitch,
const QSupportedWritingSystems &writingSystems, void *handle)
{
- QFontDatabasePrivate *d = privateDb();
+ auto *d = QFontDatabasePrivate::instance();
qCDebug(lcFontDb) << "Adding font: familyName" << familyName << "stylename" << stylename << "weight" << weight
<< "style" << style << "pixelSize" << pixelSize << "antialiased" << antialiased << "fixed" << fixedPitch;
QtFontStyle::Key styleKey;
@@ -591,8 +571,10 @@ void qt_registerFont(const QString &familyName, const QString &stylename,
void qt_registerFontFamily(const QString &familyName)
{
+ qCDebug(lcFontDb) << "Registering family" << familyName;
+
// Create uninitialized/unpopulated family
- privateDb()->family(familyName, QFontDatabasePrivate::EnsureCreated);
+ QFontDatabasePrivate::instance()->family(familyName, QFontDatabasePrivate::EnsureCreated);
}
void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
@@ -600,7 +582,9 @@ void qt_registerAliasToFontFamily(const QString &familyName, const QString &alia
if (alias.isEmpty())
return;
- QFontDatabasePrivate *d = privateDb();
+ qCDebug(lcFontDb) << "Registering alias" << alias << "to family" << familyName;
+
+ auto *d = QFontDatabasePrivate::instance();
QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
if (!f)
return;
@@ -614,7 +598,7 @@ void qt_registerAliasToFontFamily(const QString &familyName, const QString &alia
QString qt_resolveFontFamilyAlias(const QString &alias)
{
if (!alias.isEmpty()) {
- const QFontDatabasePrivate *d = privateDb();
+ const auto *d = QFontDatabasePrivate::instance();
for (int i = 0; i < d->count; ++i)
if (d->families[i]->matchesFamilyName(alias))
return d->families[i]->name;
@@ -624,7 +608,7 @@ QString qt_resolveFontFamilyAlias(const QString &alias)
bool qt_isFontFamilyPopulated(const QString &familyName)
{
- QFontDatabasePrivate *d = privateDb();
+ auto *d = QFontDatabasePrivate::instance();
QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
return f != nullptr && f->populated;
}
@@ -648,7 +632,7 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo
if (writingSystem >= QFontDatabase::WritingSystemsCount)
writingSystem = QFontDatabase::Any;
- QFontDatabasePrivate *db = privateDb();
+ auto *db = QFontDatabasePrivate::instance();
for (int i = 0; i < db->count; ++i) {
QtFontFamily *f = db->families[i];
@@ -663,7 +647,7 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo
for (int k = 0; k < foundry->count; ++k) {
QString name = foundry->name.isEmpty()
? f->name
- : f->name + QLatin1String(" [") + foundry->name + QLatin1Char(']');
+ : f->name + " ["_L1 + foundry->name + u']';
if (style == foundry->styles[k]->key.style)
preferredFallbacks.append(name);
else
@@ -675,13 +659,10 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo
return preferredFallbacks + otherFallbacks;
}
-static void initializeDb();
-
static QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script)
{
- QFontDatabasePrivate *db = privateDb();
- if (!db->count)
- initializeDb();
+ QMutexLocker locker(fontDatabaseMutex());
+ auto *db = QFontDatabasePrivate::ensureFontDatabase();
const QtFontFallbacksCacheKey cacheKey = { family, style, styleHint, script };
@@ -689,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) {
@@ -717,31 +699,7 @@ QStringList qt_fallbacksForFamily(const QString &family, QFont::Style style, QFo
return fallbacksForFamily(family, style, styleHint, script);
}
-static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt);
-
-static void initializeDb()
-{
- QFontDatabasePrivate *db = privateDb();
-
- // init by asking for the platformfontdb for the first time or after invalidation
- if (!db->count) {
- QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFontDatabase();
- for (int i = 0; i < db->applicationFonts.count(); i++) {
- if (!db->applicationFonts.at(i).properties.isEmpty())
- registerFont(&db->applicationFonts[i]);
- }
- }
-}
-
-static inline void load(const QString & = QString(), int = -1)
-{
- // Only initialize the database if it has been cleared or not initialized yet
- if (!privateDb()->count)
- initializeDb();
-}
-
-static
-QFontEngine *loadSingleEngine(int script,
+QFontEngine *QFontDatabasePrivate::loadSingleEngine(int script,
const QFontDef &request,
QtFontFamily *family, QtFontFoundry *foundry,
QtFontStyle *style, QtFontSize *size)
@@ -776,7 +734,7 @@ QFontEngine *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.family), script);
+ qPrintable(def.families.constFirst()), script);
return nullptr;
}
@@ -792,7 +750,7 @@ QFontEngine *loadSingleEngine(int script,
if (style->key.stretch != 0 && request.stretch != 0
&& (request.styleName.isEmpty() || request.styleName != style->styleName)) {
def.stretch = (request.stretch * 100 + style->key.stretch / 2) / style->key.stretch;
- } else {
+ } else if (request.stretch == QFont::AnyStretch) {
def.stretch = 100;
}
@@ -801,7 +759,7 @@ QFontEngine *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.family), script);
+ +qPrintable(def.families.constFirst()), script);
if (engine->ref.loadRelaxed() == 0)
delete engine;
return nullptr;
@@ -821,15 +779,14 @@ QFontEngine *loadSingleEngine(int script,
return engine;
}
-static
-QFontEngine *loadEngine(int script, const QFontDef &request,
+QFontEngine *QFontDatabasePrivate::loadEngine(int script, const QFontDef &request,
QtFontFamily *family, QtFontFoundry *foundry,
QtFontStyle *style, QtFontSize *size)
{
QFontEngine *engine = loadSingleEngine(script, request, family, foundry, style, size);
if (engine && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol) {
- Q_TRACE(QFontDatabase_loadEngine, request.family, 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));
@@ -868,11 +825,6 @@ QtFontStyle::~QtFontStyle()
free(pixelSizes);
}
-static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
-{
- QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data, fnt->fileName, fnt);
-}
-
static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey,
const QString &styleName = QString())
{
@@ -888,7 +840,7 @@ static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &st
break;
}
- int d = qAbs( styleKey.weight - style->key.weight );
+ int d = qAbs( (int(styleKey.weight) - int(style->key.weight)) / 10 );
if ( styleKey.stretch != 0 && style->key.stretch != 0 ) {
d += qAbs( styleKey.stretch - style->key.stretch );
@@ -913,11 +865,10 @@ static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &st
}
-static
-unsigned int bestFoundry(int script, unsigned int score, int styleStrategy,
+unsigned int QFontDatabasePrivate::bestFoundry(int script, unsigned int score, int styleStrategy,
const QtFontFamily *family, const QString &foundry_name,
QtFontStyle::Key styleKey, int pixelSize, char pitch,
- QtFontDesc *desc, const QString &styleName = QString())
+ QtFontDesc *desc, const QString &styleName)
{
Q_UNUSED(script);
Q_UNUSED(pitch);
@@ -1060,9 +1011,9 @@ static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
Tries to find the best match for a given request and family/foundry
*/
-static int match(int script, const QFontDef &request,
- const QString &family_name, const QString &foundry_name,
- QtFontDesc *desc, const QList<int> &blacklistedFamilies)
+int QFontDatabasePrivate::match(int script, const QFontDef &request, const QString &family_name,
+ const QString &foundry_name, QtFontDesc *desc, const QList<int> &blacklistedFamilies,
+ unsigned int *resultingScore)
{
int result = -1;
@@ -1074,16 +1025,18 @@ static int match(int script, const QFontDef &request,
char pitch = request.ignorePitch ? '*' : request.fixedPitch ? 'm' : 'p';
- qCDebug(lcFontMatch, "QFontDatabase::match\n"
+ qCDebug(lcFontMatch, "QFontDatabasePrivate::match\n"
" request:\n"
" family: %s [%s], script: %d\n"
+ " styleName: %s\n"
" weight: %d, style: %d\n"
" stretch: %d\n"
" pixelSize: %g\n"
" pitch: %c",
family_name.isEmpty() ? "-- first in script --" : family_name.toLatin1().constData(),
- foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(),
- script, request.weight, request.style, request.stretch, request.pixelSize, pitch);
+ foundry_name.isEmpty() ? "-- any --" : foundry_name.toLatin1().constData(), script,
+ request.styleName.isEmpty() ? "-- any --" : request.styleName.toLatin1().constData(),
+ request.weight, request.style, request.stretch, request.pixelSize, pitch);
desc->family = nullptr;
desc->foundry = nullptr;
@@ -1092,13 +1045,14 @@ static int match(int script, const QFontDef &request,
unsigned int score = ~0u;
- load(family_name, script);
+ QMutexLocker locker(fontDatabaseMutex());
+ QFontDatabasePrivate::ensureFontDatabase();
auto writingSystem = qt_writing_system_for_script(script);
if (writingSystem >= QFontDatabase::WritingSystemsCount)
writingSystem = QFontDatabase::Any;
- QFontDatabasePrivate *db = privateDb();
+ auto *db = QFontDatabasePrivate::instance();
for (int x = 0; x < db->count; ++x) {
if (blacklistedFamilies.contains(x))
continue;
@@ -1107,8 +1061,8 @@ static int match(int script, const QFontDef &request,
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))
@@ -1136,6 +1090,10 @@ static int match(int script, const QFontDef &request,
if (newscore < 10) // xlfd instead of FT... just accept it
break;
}
+
+ if (resultingScore != nullptr)
+ *resultingScore = score;
+
return result;
}
@@ -1163,9 +1121,9 @@ static QString styleStringHelper(int weight, QFont::Style style)
}
if (style == QFont::StyleItalic)
- result += QLatin1Char(' ') + QCoreApplication::translate("QFontDatabase", "Italic");
+ result += u' ' + QCoreApplication::translate("QFontDatabase", "Italic");
else if (style == QFont::StyleOblique)
- result += QLatin1Char(' ') + QCoreApplication::translate("QFontDatabase", "Oblique");
+ result += u' ' + QCoreApplication::translate("QFontDatabase", "Oblique");
if (result.isEmpty())
result = QCoreApplication::translate("QFontDatabase", "Normal", "The Normal or Regular font weight");
@@ -1230,36 +1188,29 @@ QString QFontDatabase::styleString(const QFontInfo &fontInfo)
Use the styleString() to obtain a text version of a style.
- The QFontDatabase class also supports some static functions, for
+ The QFontDatabase class provides some helper functions, for
example, standardSizes(). You can retrieve the description of a
writing system using writingSystemName(), and a sample of
characters in a writing system with writingSystemSample().
Example:
- \snippet qfontdatabase/main.cpp 0
- \snippet qfontdatabase/main.cpp 1
+ \snippet qfontdatabase/qfontdatabase_snippets.cpp 0
This example gets the list of font families, the list of
styles for each family, and the point sizes that are available for
each combination of family and style, displaying this information
in a tree view.
- \sa QFont, QFontInfo, QFontMetrics, {Character Map Example}
+ \sa QFont, QFontInfo, QFontMetrics
*/
/*!
+ \fn QFontDatabase::QFontDatabase()
+ \deprecated [6.0] Call the class methods as static functions instead.
+
Creates a font database object.
*/
-QFontDatabase::QFontDatabase()
-{
- if (Q_UNLIKELY(!qApp || !QGuiApplicationPrivate::platformIntegration()))
- qFatal("QFontDatabase: Must construct a QGuiApplication before accessing QFontDatabase");
-
- QMutexLocker locker(fontDatabaseMutex());
- createDatabase();
- d = privateDb();
-}
/*!
\enum QFontDatabase::WritingSystem
@@ -1315,24 +1266,109 @@ QFontDatabase::QFontDatabase()
*/
/*!
+ \class QFontDatabasePrivate
+ \internal
+
+ Singleton implementation of the public QFontDatabase APIs,
+ accessed through QFontDatabasePrivate::instance().
+
+ The database is organized in multiple levels:
+
+ - QFontDatabasePrivate::families
+ - QtFontFamily::foundries
+ - QtFontFoundry::styles
+ - QtFontStyle::sizes
+ - QtFontSize::pixelSize
+
+ The font database is the single source of truth when doing
+ font matching, so the database must be sufficiently filled
+ before attempting a match.
+
+ The database is populated (filled) from two sources:
+
+ 1. The system (platform's) view of the available fonts
+
+ Initiated via QFontDatabasePrivate::populateFontDatabase().
+
+ a. Can be registered lazily by family only, by calling
+ QPlatformFontDatabase::registerFontFamily(), and later
+ populated via QPlatformFontDatabase::populateFamily().
+
+ b. Or fully registered with all styles, by calling
+ QPlatformFontDatabase::registerFont().
+
+ 2. The fonts registered by the application via Qt APIs
+
+ Initiated via QFontDatabase::addApplicationFont() and
+ QFontDatabase::addApplicationFontFromData().
+
+ Application fonts are always fully registered when added.
+
+ Fonts can be added at any time, so the database may grow even
+ after QFontDatabasePrivate::populateFontDatabase() has been
+ completed.
+
+ The database does not support granular removal of fonts,
+ so if the system fonts change, or an application font is
+ removed, the font database will be cleared and then filled
+ from scratch, via QFontDatabasePrivate:invalidate() and
+ QFontDatabasePrivate::ensureFontDatabase().
+*/
+
+/*!
+ \internal
+
+ Initializes the font database if necessary and returns its
+ pointer. Mutex lock must be held when calling this function.
+*/
+QFontDatabasePrivate *QFontDatabasePrivate::ensureFontDatabase()
+{
+ auto *d = QFontDatabasePrivate::instance();
+ if (!d->populated) {
+ // 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");
+
+ auto *platformFontDatabase = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+ platformFontDatabase->populateFontDatabase();
+
+ 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);
+ }
+
+ // Note: Both application fonts and platform fonts may be added
+ // after this initial population, so the only thing we are tracking
+ // is whether we've done our part in ensuring a filled font database.
+ d->populated = true;
+ }
+ return d;
+}
+
+/*!
Returns a sorted list of the available writing systems. This is
list generated from information about all installed fonts on the
system.
\sa families()
*/
-QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() const
+QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems()
{
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)();
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
quint64 writingSystemsFound = 0;
static_assert(WritingSystemsCount < 64);
for (int i = 0; i < d->count; ++i) {
QtFontFamily *family = d->families[i];
- family->ensurePopulated();
+ if (!family->ensurePopulated())
+ continue;
if (family->count == 0)
continue;
@@ -1361,14 +1397,13 @@ QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems() const
\sa families()
*/
-QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family) const
+QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString &family)
{
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)();
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QList<WritingSystem> list;
QtFontFamily *f = d->family(familyName);
@@ -1394,11 +1429,10 @@ QList<QFontDatabase::WritingSystem> QFontDatabase::writingSystems(const QString
\sa writingSystems()
*/
-QStringList QFontDatabase::families(WritingSystem writingSystem) const
+QStringList QFontDatabase::families(WritingSystem writingSystem)
{
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)();
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QStringList flist;
for (int i = 0; i < d->count; i++) {
@@ -1406,7 +1440,8 @@ QStringList QFontDatabase::families(WritingSystem writingSystem) const
if (f->populated && f->count == 0)
continue;
if (writingSystem != Any) {
- f->ensurePopulated();
+ if (!f->ensurePopulated())
+ continue;
if (f->writingSystems[writingSystem] != QtFontFamily::Supported)
continue;
}
@@ -1417,9 +1452,9 @@ QStringList QFontDatabase::families(WritingSystem writingSystem) const
QString str = f->name;
QString foundry = f->foundries[j]->name;
if (!foundry.isEmpty()) {
- str += QLatin1String(" [");
+ str += " ["_L1;
str += foundry;
- str += QLatin1Char(']');
+ str += u']';
}
flist.append(str);
}
@@ -1435,14 +1470,13 @@ QStringList QFontDatabase::families(WritingSystem writingSystem) const
\sa families()
*/
-QStringList QFontDatabase::styles(const QString &family) const
+QStringList QFontDatabase::styles(const QString &family)
{
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QStringList l;
QtFontFamily *f = d->family(familyName);
@@ -1477,7 +1511,7 @@ QStringList QFontDatabase::styles(const QString &family) const
*/
bool QFontDatabase::isFixedPitch(const QString &family,
- const QString &style) const
+ const QString &style)
{
Q_UNUSED(style);
@@ -1485,8 +1519,7 @@ bool QFontDatabase::isFixedPitch(const QString &family,
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QtFontFamily *f = d->family(familyName);
return (f && f->fixedPitch);
@@ -1503,15 +1536,14 @@ bool QFontDatabase::isFixedPitch(const QString &family,
\sa isScalable(), isSmoothlyScalable()
*/
bool QFontDatabase::isBitmapScalable(const QString &family,
- const QString &style) const
+ const QString &style)
{
bool bitmapScalable = false;
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QtFontFamily *f = d->family(familyName);
if (!f) return bitmapScalable;
@@ -1543,39 +1575,44 @@ bool QFontDatabase::isBitmapScalable(const QString &family,
\sa isScalable(), isBitmapScalable()
*/
-bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style) const
+bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &style)
{
bool smoothScalable = false;
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QtFontFamily *f = d->family(familyName);
if (!f) {
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;
}
}
}
if (!f) return smoothScalable;
- QtFontStyle::Key styleKey(style);
+ const QtFontStyle::Key styleKey(style);
for (int j = 0; j < f->count; j++) {
QtFontFoundry *foundry = f->foundries[j];
if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
- for (int k = 0; k < foundry->count; k++)
- if ((style.isEmpty() ||
- foundry->styles[k]->styleName == style ||
- foundry->styles[k]->key == styleKey) && foundry->styles[k]->smoothScalable) {
- smoothScalable = true;
+ for (int k = 0; k < foundry->count; k++) {
+ const QtFontStyle *fontStyle = foundry->styles[k];
+ smoothScalable =
+ fontStyle->smoothScalable
+ && ((style.isEmpty()
+ || fontStyle->styleName == style
+ || fontStyle->key == styleKey)
+ || (fontStyle->styleName.isEmpty()
+ && style == styleStringHelper(fontStyle->key.weight,
+ QFont::Style(fontStyle->key.style))));
+ if (smoothScalable)
goto end;
- }
+ }
}
}
end:
@@ -1589,7 +1626,7 @@ bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &sty
\sa isBitmapScalable(), isSmoothlyScalable()
*/
bool QFontDatabase::isScalable(const QString &family,
- const QString &style) const
+ const QString &style)
{
QMutexLocker locker(fontDatabaseMutex());
if (isSmoothlyScalable(family, style))
@@ -1605,7 +1642,7 @@ bool QFontDatabase::isScalable(const QString &family,
\sa smoothSizes(), standardSizes()
*/
QList<int> QFontDatabase::pointSizes(const QString &family,
- const QString &styleName)
+ const QString &styleName)
{
if (QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fontsAlwaysScalable())
return standardSizes();
@@ -1615,8 +1652,7 @@ QList<int> QFontDatabase::pointSizes(const QString &family,
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QList<int> sizes;
@@ -1641,7 +1677,7 @@ QList<int> QFontDatabase::pointSizes(const QString &family,
const QtFontSize *size = style->pixelSizes + l;
if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
- const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
+ const int pointSize = qRound(size->pixelSize * 72.0 / dpi);
if (! sizes.contains(pointSize))
sizes.append(pointSize);
}
@@ -1663,14 +1699,12 @@ QList<int> QFontDatabase::pointSizes(const QString &family,
returned.
*/
QFont QFontDatabase::font(const QString &family, const QString &style,
- int pointSize) const
+ int pointSize)
{
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
-
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QtFontFoundry allStyles(foundryName);
QtFontFamily *f = d->family(familyName);
@@ -1690,7 +1724,7 @@ QFont QFontDatabase::font(const QString &family, const QString &style,
if (!s) // no styles found?
return QGuiApplication::font();
- QFont fnt(family, pointSize, s->key.weight);
+ QFont fnt(QStringList{family}, pointSize, s->key.weight);
fnt.setStyle((QFont::Style)s->key.style);
if (!s->styleName.isEmpty())
fnt.setStyleName(s->styleName);
@@ -1717,8 +1751,7 @@ QList<int> QFontDatabase::smoothSizes(const QString &family,
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QList<int> sizes;
@@ -1743,7 +1776,7 @@ QList<int> QFontDatabase::smoothSizes(const QString &family,
const QtFontSize *size = style->pixelSizes + l;
if (size->pixelSize != 0 && size->pixelSize != SMOOTH_SCALABLE) {
- const uint pointSize = qRound(size->pixelSize * 72.0 / dpi);
+ const int pointSize = qRound(size->pixelSize * 72.0 / dpi);
if (! sizes.contains(pointSize))
sizes.append(pointSize);
}
@@ -1776,14 +1809,13 @@ QList<int> QFontDatabase::standardSizes()
\sa weight(), bold()
*/
-bool QFontDatabase::italic(const QString &family, const QString &style) const
+bool QFontDatabase::italic(const QString &family, const QString &style)
{
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QtFontFoundry allStyles(foundryName);
QtFontFamily *f = d->family(familyName);
@@ -1810,14 +1842,13 @@ bool QFontDatabase::italic(const QString &family, const QString &style) const
\sa italic(), weight()
*/
bool QFontDatabase::bold(const QString &family,
- const QString &style) const
+ const QString &style)
{
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QtFontFoundry allStyles(foundryName);
QtFontFamily *f = d->family(familyName);
@@ -1846,14 +1877,13 @@ bool QFontDatabase::bold(const QString &family,
\sa italic(), bold()
*/
int QFontDatabase::weight(const QString &family,
- const QString &style) const
+ const QString &style)
{
QString familyName, foundryName;
parseFontName(family, foundryName, familyName);
QMutexLocker locker(fontDatabaseMutex());
-
- QT_PREPEND_NAMESPACE(load)(familyName);
+ QFontDatabasePrivate *d = QFontDatabasePrivate::ensureFontDatabase();
QtFontFoundry allStyles(foundryName);
QtFontFamily *f = d->family(familyName);
@@ -1875,12 +1905,24 @@ int QFontDatabase::weight(const QString &family,
/*! \internal */
-bool QFontDatabase::hasFamily(const QString &family) const
+bool QFontDatabase::hasFamily(const QString &family)
{
QString parsedFamily, foundry;
parseFontName(family, foundry, parsedFamily);
- const QString familyAlias = resolveFontFamilyAlias(parsedFamily);
- return families().contains(familyAlias, Qt::CaseInsensitive);
+ const QString familyAlias = QFontDatabasePrivate::resolveFontFamilyAlias(parsedFamily);
+
+ 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;
}
@@ -1896,7 +1938,7 @@ bool QFontDatabase::hasFamily(const QString &family) const
\sa families()
*/
-bool QFontDatabase::isPrivateFamily(const QString &family) const
+bool QFontDatabase::isPrivateFamily(const QString &family)
{
return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->isPrivateFontFamily(family);
}
@@ -2019,106 +2061,99 @@ QString QFontDatabase::writingSystemName(WritingSystem writingSystem)
return QCoreApplication::translate("QFontDatabase", name);
}
-static QStringView writing_system_sample(QFontDatabase::WritingSystem writingSystem)
-{
- switch (writingSystem) {
- case QFontDatabase::Any:
- case QFontDatabase::Symbol:
- // show only ascii characters
- return u"AaBbzZ";
- case QFontDatabase::Latin:
- // This is cheating... we only show latin-1 characters so that we don't
- // end up loading lots of fonts - at least on X11...
- return u"Aa\x00C3\x00E1Zz";
- case QFontDatabase::Greek:
- return u"\x0393\x03B1\x03A9\x03C9";
- case QFontDatabase::Cyrillic:
- return u"\x0414\x0434\x0436\x044f";
- case QFontDatabase::Armenian:
- return u"\x053f\x054f\x056f\x057f";
- case QFontDatabase::Hebrew:
- return u"\x05D0\x05D1\x05D2\x05D3";
- case QFontDatabase::Arabic:
- return u"\x0623\x0628\x062C\x062F\x064A\x0629\x0020\x0639\x0631\x0628\x064A\x0629";
- case QFontDatabase::Syriac:
- return u"\x0715\x0725\x0716\x0726";
- case QFontDatabase::Thaana:
- return u"\x0784\x0794\x078c\x078d";
- case QFontDatabase::Devanagari:
- return u"\x0905\x0915\x0925\x0935";
- case QFontDatabase::Bengali:
- return u"\x0986\x0996\x09a6\x09b6";
- case QFontDatabase::Gurmukhi:
- return u"\x0a05\x0a15\x0a25\x0a35";
- case QFontDatabase::Gujarati:
- return u"\x0a85\x0a95\x0aa5\x0ab5";
- case QFontDatabase::Oriya:
- return u"\x0b06\x0b16\x0b2b\x0b36";
- case QFontDatabase::Tamil:
- return u"\x0b89\x0b99\x0ba9\x0bb9";
- case QFontDatabase::Telugu:
- return u"\x0c05\x0c15\x0c25\x0c35";
- case QFontDatabase::Kannada:
- return u"\x0c85\x0c95\x0ca5\x0cb5";
- case QFontDatabase::Malayalam:
- return u"\x0d05\x0d15\x0d25\x0d35";
- case QFontDatabase::Sinhala:
- return u"\x0d90\x0da0\x0db0\x0dc0";
- case QFontDatabase::Thai:
- return u"\x0e02\x0e12\x0e22\x0e32";
- case QFontDatabase::Lao:
- return u"\x0e8d\x0e9d\x0ead\x0ebd";
- case QFontDatabase::Tibetan:
- return u"\x0f00\x0f01\x0f02\x0f03";
- case QFontDatabase::Myanmar:
- return u"\x1000\x1001\x1002\x1003";
- case QFontDatabase::Georgian:
- return u"\x10a0\x10b0\x10c0\x10d0";
- case QFontDatabase::Khmer:
- return u"\x1780\x1790\x17b0\x17c0";
- case QFontDatabase::SimplifiedChinese:
- return u"\x4e2d\x6587\x8303\x4f8b";
- case QFontDatabase::TraditionalChinese:
- return u"\x4e2d\x6587\x7bc4\x4f8b";
- case QFontDatabase::Japanese:
- return u"\x30b5\x30f3\x30d7\x30eb\x3067\x3059";
- case QFontDatabase::Korean:
- return u"\xac00\xac11\xac1a\xac2f";
- case QFontDatabase::Vietnamese:
- return u"\x1ED7\x1ED9\x1ED1\x1ED3";
- case QFontDatabase::Ogham:
- return u"\x1681\x1682\x1683\x1684";
- case QFontDatabase::Runic:
- return u"\x16a0\x16a1\x16a2\x16a3";
- case QFontDatabase::Nko:
- return u"\x7ca\x7cb\x7cc\x7cd";
- default:
- return nullptr;
- }
-}
-
/*!
Returns a string with sample characters from \a writingSystem.
*/
QString QFontDatabase::writingSystemSample(WritingSystem writingSystem)
{
- return writing_system_sample(writingSystem).toString();
+ return [&]() -> QStringView {
+ switch (writingSystem) {
+ case QFontDatabase::Any:
+ case QFontDatabase::Symbol:
+ // show only ascii characters
+ return u"AaBbzZ";
+ case QFontDatabase::Latin:
+ // This is cheating... we only show latin-1 characters so that we don't
+ // end up loading lots of fonts - at least on X11...
+ return u"Aa\x00C3\x00E1Zz";
+ case QFontDatabase::Greek:
+ return u"\x0393\x03B1\x03A9\x03C9";
+ case QFontDatabase::Cyrillic:
+ return u"\x0414\x0434\x0436\x044f";
+ case QFontDatabase::Armenian:
+ return u"\x053f\x054f\x056f\x057f";
+ case QFontDatabase::Hebrew:
+ return u"\x05D0\x05D1\x05D2\x05D3";
+ case QFontDatabase::Arabic:
+ return u"\x0623\x0628\x062C\x062F\x064A\x0629\x0020\x0639\x0631\x0628\x064A\x0629";
+ case QFontDatabase::Syriac:
+ return u"\x0715\x0725\x0716\x0726";
+ case QFontDatabase::Thaana:
+ return u"\x0784\x0794\x078c\x078d";
+ case QFontDatabase::Devanagari:
+ return u"\x0905\x0915\x0925\x0935";
+ case QFontDatabase::Bengali:
+ return u"\x0986\x0996\x09a6\x09b6";
+ case QFontDatabase::Gurmukhi:
+ return u"\x0a05\x0a15\x0a25\x0a35";
+ case QFontDatabase::Gujarati:
+ return u"\x0a85\x0a95\x0aa5\x0ab5";
+ case QFontDatabase::Oriya:
+ return u"\x0b06\x0b16\x0b2b\x0b36";
+ case QFontDatabase::Tamil:
+ return u"\x0b89\x0b99\x0ba9\x0bb9";
+ case QFontDatabase::Telugu:
+ return u"\x0c05\x0c15\x0c25\x0c35";
+ case QFontDatabase::Kannada:
+ return u"\x0c85\x0c95\x0ca5\x0cb5";
+ case QFontDatabase::Malayalam:
+ return u"\x0d05\x0d15\x0d25\x0d35";
+ case QFontDatabase::Sinhala:
+ return u"\x0d90\x0da0\x0db0\x0dc0";
+ case QFontDatabase::Thai:
+ return u"\x0e02\x0e12\x0e22\x0e32";
+ case QFontDatabase::Lao:
+ return u"\x0e8d\x0e9d\x0ead\x0ebd";
+ case QFontDatabase::Tibetan:
+ return u"\x0f00\x0f01\x0f02\x0f03";
+ case QFontDatabase::Myanmar:
+ return u"\x1000\x1001\x1002\x1003";
+ case QFontDatabase::Georgian:
+ return u"\x10a0\x10b0\x10c0\x10d0";
+ case QFontDatabase::Khmer:
+ return u"\x1780\x1790\x17b0\x17c0";
+ case QFontDatabase::SimplifiedChinese:
+ return u"\x4e2d\x6587\x8303\x4f8b";
+ case QFontDatabase::TraditionalChinese:
+ return u"\x4e2d\x6587\x7bc4\x4f8b";
+ case QFontDatabase::Japanese:
+ return u"\x30b5\x30f3\x30d7\x30eb\x3067\x3059";
+ case QFontDatabase::Korean:
+ return u"\xac00\xac11\xac1a\xac2f";
+ case QFontDatabase::Vietnamese:
+ return u"\x1ED7\x1ED9\x1ED1\x1ED3";
+ case QFontDatabase::Ogham:
+ return u"\x1681\x1682\x1683\x1684";
+ case QFontDatabase::Runic:
+ return u"\x16a0\x16a1\x16a2\x16a3";
+ case QFontDatabase::Nko:
+ return u"\x7ca\x7cb\x7cc\x7cd";
+ default:
+ return nullptr;
+ }
+ }().toString();
}
-
-void QFontDatabase::parseFontName(const QString &name, QString &foundry, QString &family)
+void QFontDatabasePrivate::parseFontName(const QString &name, QString &foundry, QString &family)
{
QT_PREPEND_NAMESPACE(parseFontName)(name, foundry, family);
}
-void QFontDatabase::createDatabase()
-{ initializeDb(); }
-
// used from qfontengine_ft.cpp
Q_GUI_EXPORT QByteArray qt_fontdata_from_index(int index)
{
QMutexLocker locker(fontDatabaseMutex());
- return privateDb()->applicationFonts.value(index).data;
+ return QFontDatabasePrivate::instance()->applicationFonts.value(index).data;
}
int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &fileName)
@@ -2130,35 +2165,36 @@ int QFontDatabasePrivate::addAppFont(const QByteArray &fontData, const QString &
Q_TRACE(QFontDatabasePrivate_addAppFont, fileName);
int i;
- for (i = 0; i < applicationFonts.count(); ++i)
- if (applicationFonts.at(i).properties.isEmpty())
+ 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())
- font.fileName = QLatin1String(":qmemoryfonts/") + QString::number(i);
+ font.fileName = ":qmemoryfonts/"_L1 + QString::number(i);
- bool wasEmpty = privateDb()->count == 0;
- registerFont(&font);
+ auto *platformFontDatabase = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+ platformFontDatabase->addApplicationFont(font.data, font.fileName, &font);
if (font.properties.isEmpty())
return -1;
applicationFonts[i] = font;
- // If the cache has not yet been populated, we need to reload the application font later
- if (wasEmpty)
- invalidate();
- else
- emit qApp->fontDatabaseChanged();
+ // The font cache may have cached lookups for the font that was now
+ // loaded, so it has to be flushed.
+ QFontCache::instance()->clear();
+
+ emit qApp->fontDatabaseChanged();
+
return i;
}
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;
@@ -2172,13 +2208,12 @@ bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
with removeApplicationFont() or to retrieve the list of family names contained
in the font.
+//! [add-application-font-doc]
The function returns -1 if the font could not be loaded.
Currently only TrueType fonts, TrueType font collections, and OpenType fonts are
supported.
-
- \note Adding application fonts on Unix/X11 platforms without fontconfig is
- currently not supported.
+//! [add-application-font-doc]
\sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
*/
@@ -2195,7 +2230,7 @@ int QFontDatabase::addApplicationFont(const QString &fileName)
data = f.readAll();
}
QMutexLocker locker(fontDatabaseMutex());
- return privateDb()->addAppFont(data, fileName);
+ return QFontDatabasePrivate::instance()->addAppFont(data, fileName);
}
/*!
@@ -2206,19 +2241,14 @@ int QFontDatabase::addApplicationFont(const QString &fileName)
with removeApplicationFont() or to retrieve the list of family names contained
in the font.
- The function returns -1 if the font could not be loaded.
-
- Currently only TrueType fonts and TrueType font collections are supported.
-
- \b{Note:} Adding application fonts on Unix/X11 platforms without fontconfig is
- currently not supported.
+ \include qfontdatabase.cpp add-application-font-doc
\sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont()
*/
int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData)
{
QMutexLocker locker(fontDatabaseMutex());
- return privateDb()->addAppFont(fontData, QString() /* fileName */);
+ return QFontDatabasePrivate::instance()->addAppFont(fontData, QString() /* fileName */);
}
/*!
@@ -2232,11 +2262,12 @@ int QFontDatabase::addApplicationFontFromData(const QByteArray &fontData)
QStringList QFontDatabase::applicationFontFamilies(int id)
{
QMutexLocker locker(fontDatabaseMutex());
+ auto *d = QFontDatabasePrivate::instance();
QStringList ret;
- ret.reserve(privateDb()->applicationFonts.value(id).properties.size());
+ ret.reserve(d->applicationFonts.value(id).properties.size());
- for (const auto &properties : privateDb()->applicationFonts.value(id).properties)
+ for (const auto &properties : d->applicationFonts.value(id).properties)
ret.append(properties.familyName);
return ret;
@@ -2294,8 +2325,8 @@ bool QFontDatabase::removeApplicationFont(int handle)
{
QMutexLocker locker(fontDatabaseMutex());
- QFontDatabasePrivate *db = privateDb();
- if (handle < 0 || handle >= db->applicationFonts.count())
+ auto *db = QFontDatabasePrivate::instance();
+ if (handle < 0 || handle >= db->applicationFonts.size())
return false;
db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont();
@@ -2320,7 +2351,7 @@ bool QFontDatabase::removeAllApplicationFonts()
{
QMutexLocker locker(fontDatabaseMutex());
- QFontDatabasePrivate *db = privateDb();
+ auto *db = QFontDatabasePrivate::instance();
if (!db || db->applicationFonts.isEmpty())
return false;
@@ -2330,20 +2361,148 @@ bool QFontDatabase::removeAllApplicationFonts()
}
/*!
- \internal
+ \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()
*/
-QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
+void QFontDatabase::addApplicationFallbackFontFamily(QChar::Script script, const QString &familyName)
{
QMutexLocker locker(fontDatabaseMutex());
- if (!privateDb()->count)
- initializeDb();
+ 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,
+ int script,
+ bool preferScriptOverFamily)
+{
+ QMutexLocker locker(fontDatabaseMutex());
+ ensureFontDatabase();
QFontEngine *engine;
+#ifdef Q_OS_WIN
+ const QFontDef request = static_cast<QWindowsFontDatabaseBase *>(
+ QGuiApplicationPrivate::platformIntegration()->fontDatabase())
+ ->sanitizeRequest(req);
+#else
+ const QFontDef &request = req;
+#endif
+
#if defined(QT_BUILD_INTERNAL)
// For testing purpose only, emulates an exact-matching monospace font
- if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) {
+ if (qt_enable_test_font && request.families.first() == "__Qt__Box__Engine__"_L1) {
engine = new QTestFontEngine(request.pixelSize);
engine->fontDef = request;
return engine;
@@ -2363,22 +2522,36 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
return engine;
}
+ if (request.pixelSize > 0xffff) {
+ // Stop absurd requests reaching the engines; pixel size is assumed to fit ushort
+ qCDebug(lcFontMatch, "Rejecting request for pixel size %g2, returning box engine", double(request.pixelSize));
+ return new QFontEngineBox(32); // not request.pixelSize, to avoid overflow/DOS
+ }
+
QString family_name, foundry_name;
- const QString requestFamily = request.families.size() > 0 ? request.families.at(0) : request.family;
+ const QString requestFamily = request.families.at(0);
parseFontName(requestFamily, foundry_name, family_name);
QtFontDesc desc;
QList<int> blackListed;
- int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
- if (index < 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
- // We populated familiy aliases (e.g. localized families), so try again
+ unsigned int score = UINT_MAX;
+ int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed, &score);
+ if (score > 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
+ // We populated family 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
// and we will be out of sync with the matched font.
- if (fontDef.families.isEmpty() && fontDef.family.isEmpty())
+ if (fontDef.families.isEmpty())
fontDef.families = QStringList(desc.family->name);
engine = loadEngine(script, fontDef, desc.family, desc.foundry, desc.style, desc.size);
@@ -2407,17 +2580,17 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
for (int i = 0; !engine && i < fallbacks.size(); i++) {
QFontDef def = request;
- def.family = fallbacks.at(i);
+ def.families = QStringList(fallbacks.at(i));
QFontCache::Key key(def, script, multi ? 1 : 0);
engine = fontCache->findEngine(key);
if (!engine) {
QtFontDesc desc;
do {
- index = match(multi ? QChar::Script_Common : script, def, def.family, QLatin1String(""), &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() && loadDef.family.isEmpty())
- loadDef.family = desc.family->name;
+ if (loadDef.families.isEmpty())
+ loadDef.families = QStringList(desc.family->name);
engine = loadEngine(script, loadDef, desc.family, desc.foundry, desc.style, desc.size);
if (engine)
initFontDef(desc, loadDef, &engine->fontDef, multi);
@@ -2438,7 +2611,7 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
return engine;
}
-void QFontDatabase::load(const QFontPrivate *d, int script)
+void QFontDatabasePrivate::load(const QFontPrivate *d, int script)
{
QFontDef req = d->request;
@@ -2457,8 +2630,6 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
// look for the requested font in the engine data cache
// note: fallBackFamilies are not respected in the EngineData cache key;
// join them with the primary selection family to avoid cache misses
- if (!d->request.family.isEmpty())
- req.family = fallBackFamilies.join(QLatin1Char(','));
if (!d->request.families.isEmpty())
req.families = fallBackFamilies;
@@ -2477,7 +2648,7 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
QFontEngine *fe = nullptr;
- Q_TRACE(QFontDatabase_load, req.family, req.pointSize);
+ Q_TRACE(QFontDatabase_load, req.families.join(QLatin1Char(';')), req.pointSize);
req.fallBackFamilies = fallBackFamilies;
if (!req.fallBackFamilies.isEmpty())
@@ -2491,9 +2662,12 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
family_list << req.families.at(0);
// add the default family
- QString defaultFamily = QGuiApplication::font().family();
- if (! family_list.contains(defaultFamily))
- family_list << defaultFamily;
+ const auto families = QGuiApplication::font().families();
+ if (!families.isEmpty()) {
+ QString defaultFamily = families.first();
+ if (! family_list.contains(defaultFamily))
+ family_list << defaultFamily;
+ }
}
@@ -2504,7 +2678,7 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
for (; !fe && it != end; ++it) {
req.families = QStringList(*it);
- fe = QFontDatabase::findFont(req, script);
+ fe = QFontDatabasePrivate::findFont(req, script);
if (fe) {
if (fe->type() == QFontEngine::Box && !req.families.at(0).isEmpty()) {
if (fe->ref.loadRelaxed() == 0)
@@ -2534,7 +2708,7 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
}
}
-QString QFontDatabase::resolveFontFamilyAlias(const QString &family)
+QString QFontDatabasePrivate::resolveFontFamilyAlias(const QString &family)
{
return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family);
}
@@ -2547,7 +2721,7 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script
return families;
}
- QFontDatabasePrivate *db = privateDb();
+ auto *db = QFontDatabasePrivate::instance();
QMultiMap<uint, QString> supported;
for (int i = 0; i < families.size(); ++i) {
const QString &family = families.at(i);
@@ -2556,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;
}
}
@@ -2575,3 +2749,5 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script
QT_END_NAMESPACE
+#include "moc_qfontdatabase.cpp"
+