diff options
Diffstat (limited to 'src/gui/text/qfontdatabase.cpp')
-rw-r--r-- | src/gui/text/qfontdatabase.cpp | 419 |
1 files changed, 416 insertions, 3 deletions
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 61c93dc2ac..b8ac7efb6c 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -55,6 +55,8 @@ #include <qpa/qplatformfontdatabase.h> #include <qpa/qplatformtheme.h> +#include <QtCore/qmath.h> + #include <stdlib.h> #include <limits.h> #include <algorithm> @@ -654,9 +656,200 @@ QMutex *qt_fontdatabase_mutex() return fontDatabaseMutex(); } -QT_BEGIN_INCLUDE_NAMESPACE -# include "qfontdatabase_qpa.cpp" -QT_END_INCLUDE_NAMESPACE + +void qt_registerFont(const QString &familyName, const QString &stylename, + const QString &foundryname, int weight, + QFont::Style style, int stretch, bool antialiased, + bool scalable, int pixelSize, bool fixedPitch, + const QSupportedWritingSystems &writingSystems, void *handle) +{ + QFontDatabasePrivate *d = privateDb(); +// qDebug() << "Adding font" << familyName << weight << style << pixelSize << antialiased; + QtFontStyle::Key styleKey; + styleKey.style = style; + styleKey.weight = weight; + styleKey.stretch = stretch; + QtFontFamily *f = d->family(familyName, true); + f->fixedPitch = fixedPitch; + + for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) { + if (writingSystems.supported(QFontDatabase::WritingSystem(i))) + f->writingSystems[i] = QtFontFamily::Supported; + } + + QtFontFoundry *foundry = f->foundry(foundryname, true); + QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true); + fontStyle->smoothScalable = scalable; + fontStyle->antialiased = antialiased; + QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true); + if (size->handle) { + QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration(); + if (integration) + integration->fontDatabase()->releaseHandle(size->handle); + } + size->handle = handle; +} + +void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias) +{ + if (alias.isEmpty()) + return; + + QFontDatabasePrivate *d = privateDb(); + QtFontFamily *f = d->family(familyName, false); + if (!f) + return; + + if (f->aliases.contains(alias, Qt::CaseInsensitive)) + return; + + f->aliases.push_back(alias); +} + +QString qt_resolveFontFamilyAlias(const QString &alias) +{ + if (!alias.isEmpty()) { + const QFontDatabasePrivate *d = privateDb(); + for (int i = 0; i < d->count; ++i) + if (d->families[i]->matchesFamilyName(alias)) + return d->families[i]->name; + } + return alias; +} + +static QStringList fallbackFamilies(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) +{ + QStringList retList = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->fallbacksForFamily(family,style,styleHint,script); + QFontDatabasePrivate *db = privateDb(); + + QStringList::iterator i; + for (i = retList.begin(); i != retList.end(); ++i) { + bool contains = false; + for (int j = 0; j < db->count; j++) { + if (db->families[j]->matchesFamilyName(*i)) { + contains = true; + break; + } + } + if (!contains) { + i = retList.erase(i); + i--; + } + } + return retList; +} + +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(); + + if (db->reregisterAppFonts) { + for (int i = 0; i < db->applicationFonts.count(); i++) { + if (!db->applicationFonts.at(i).families.isEmpty()) + registerFont(&db->applicationFonts[i]); + } + db->reregisterAppFonts = false; + } +} + +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, + const QFontDef &request, + QtFontFoundry *foundry, + QtFontStyle *style, QtFontSize *size) +{ + Q_UNUSED(foundry); + + Q_ASSERT(size); + QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); + int pixelSize = size->pixelSize; + if (!pixelSize || (style->smoothScalable && pixelSize == SMOOTH_SCALABLE) + || pfdb->fontsAlwaysScalable()) { + pixelSize = request.pixelSize; + } + + QFontDef def = request; + def.pixelSize = pixelSize; + + QFontCache::Key key(def,script); + QFontEngine *engine = QFontCache::instance()->findEngine(key); + if (!engine) { + engine = pfdb->fontEngine(def, size->handle); + if (engine) { + // Also check for OpenType tables when using complex scripts + if (!engine->supportsScript(QChar::Script(script))) { + qWarning(" OpenType support missing for script %d", script); + if (engine->ref.load() == 0) + delete engine; + return 0; + } + + QFontCache::instance()->insertEngine(key, engine); + } + } + return engine; +} + +static +QFontEngine *loadEngine(int script, const QFontDef &request, + QtFontFamily *family, QtFontFoundry *foundry, + QtFontStyle *style, QtFontSize *size) +{ + + QFontEngine *engine = loadSingleEngine(script, request, foundry, style, size); + //make sure that the db has all fallback families + if (engine && engine->type() != QFontEngine::Multi + && !(request.styleStrategy & QFont::NoFontMerging) && !engine->symbol ) { + + if (family && !family->askedForFallback) { + QFont::Style fontStyle = QFont::Style(style->key.style); + QFont::StyleHint styleHint = QFont::StyleHint(request.styleHint); + if (styleHint == QFont::AnyStyle && request.fixedPitch) + styleHint = QFont::TypeWriter; + family->fallbackFamilies = fallbackFamilies(family->name, fontStyle, styleHint, QChar::Script(script)); + + family->askedForFallback = true; + } + + QStringList fallbacks = privateDb()->fallbackFamilies; + if (family && !family->fallbackFamilies.isEmpty()) + fallbacks = family->fallbackFamilies; + + QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); + QFontEngineMulti *pfMultiEngine = pfdb->fontEngineMulti(engine, QChar::Script(script)); + pfMultiEngine->setFallbackFamiliesList(fallbacks); + engine = pfMultiEngine; + + // Cache Multi font engine as well in case we got the single + // font engine when we are actually looking for a Multi one + QFontCache::Key key(request, script, 1); + QFontCache::instance()->insertEngine(key, engine); + } + + return engine; +} + +static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) +{ + QFontDatabasePrivate *db = privateDb(); + + fnt->families = QGuiApplicationPrivate::platformIntegration()->fontDatabase()->addApplicationFont(fnt->data,fnt->fileName); + + db->reregisterAppFonts = true; +} static QtFontStyle *bestStyle(QtFontFoundry *foundry, const QtFontStyle::Key &styleKey, const QString &styleName = QString()) @@ -2146,6 +2339,20 @@ QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type) \sa removeAllApplicationFonts(), addApplicationFont(), addApplicationFontFromData() */ +bool QFontDatabase::removeApplicationFont(int handle) +{ + QMutexLocker locker(fontDatabaseMutex()); + + QFontDatabasePrivate *db = privateDb(); + if (handle < 0 || handle >= db->applicationFonts.count()) + return false; + + db->applicationFonts[handle] = QFontDatabasePrivate::ApplicationFont(); + + db->reregisterAppFonts = true; + db->invalidate(); + return true; +} /*! \fn bool QFontDatabase::removeAllApplicationFonts() @@ -2159,6 +2366,18 @@ QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type) \sa removeApplicationFont(), addApplicationFont(), addApplicationFontFromData() */ +bool QFontDatabase::removeAllApplicationFonts() +{ + QMutexLocker locker(fontDatabaseMutex()); + + QFontDatabasePrivate *db = privateDb(); + if (db->applicationFonts.isEmpty()) + return false; + + db->applicationFonts.clear(); + db->invalidate(); + return true; +} /*! \fn bool QFontDatabase::supportsThreadedFontRendering() @@ -2174,6 +2393,200 @@ QFont QFontDatabase::systemFont(QFontDatabase::SystemFont type) \sa {Thread-Support in Qt Modules#Painting In Threads}{Painting In Threads} */ +// QT_DEPRECATED_SINCE(5, 2) +bool QFontDatabase::supportsThreadedFontRendering() +{ + return true; +} + +/*! + \internal +*/ +QFontEngine * +QFontDatabase::findFont(int script, const QFontPrivate *fp, + const QFontDef &request, bool multi) +{ + QMutexLocker locker(fontDatabaseMutex()); + + const int force_encoding_id = -1; + + if (!privateDb()->count) + initializeDb(); + + QFontEngine *engine; + QFontCache::Key key(request, script, multi ? 1 : 0); + engine = QFontCache::instance()->findEngine(key); + if (engine) { + FM_DEBUG("Cache hit level 1"); + return engine; + } + + QString family_name, foundry_name; + + parseFontName(request.family, foundry_name, family_name); + + if (qt_enable_test_font && request.family == QLatin1String("__Qt__Box__Engine__")) { + engine =new QTestFontEngine(request.pixelSize); + engine->fontDef = request; + } + + QtFontDesc desc; + QList<int> blackListed; + int index = match(script, request, family_name, foundry_name, force_encoding_id, &desc, blackListed); + if (index >= 0) { + engine = loadEngine(script, request, desc.family, desc.foundry, desc.style, desc.size); + if (!engine) + blackListed.append(index); + } else { + FM_DEBUG(" NO MATCH FOUND\n"); + } + + if (engine && engine->type() != QFontEngine::TestFontEngine) { + initFontDef(desc, request, &engine->fontDef, engine->type() == QFontEngine::Multi); + + if (fp) { + QFontDef def = request; + if (def.family.isEmpty()) { + def.family = fp->request.family; + def.family = def.family.left(def.family.indexOf(QLatin1Char(','))); + } + } + } + + if (!engine) { + if (!request.family.isEmpty()) { + QStringList fallbacks = request.fallBackFamilies + + fallbackFamilies(request.family, + QFont::Style(request.style), + QFont::StyleHint(request.styleHint), + QChar::Script(script)); + if (script > QChar::Script_Common) + fallbacks += QString(); // Find the first font matching the specified script. + + for (int i = 0; !engine && i < fallbacks.size(); i++) { + QFontDef def = request; + def.family = fallbacks.at(i); + QFontCache::Key key(def, script, multi ? 1 : 0); + engine = QFontCache::instance()->findEngine(key); + if (!engine) { + QtFontDesc desc; + do { + index = match(script, def, def.family, QLatin1String(""), 0, &desc, blackListed); + if (index >= 0) { + QFontDef loadDef = def; + if (loadDef.family.isEmpty()) + loadDef.family = desc.family->name; + engine = loadEngine(script, loadDef, desc.family, desc.foundry, desc.style, desc.size); + if (engine) + initFontDef(desc, loadDef, &engine->fontDef, engine->type() == QFontEngine::Multi); + else + blackListed.append(index); + } + } while (index >= 0 && !engine); + } + } + } + + if (!engine) + engine = new QFontEngineBox(request.pixelSize); + + FM_DEBUG("returning box engine"); + } + + if (fp && fp->dpi > 0) { + engine->fontDef.pointSize = qreal(double((engine->fontDef.pixelSize * 72) / fp->dpi)); + } else { + engine->fontDef.pointSize = request.pointSize; + } + + return engine; +} + +void QFontDatabase::load(const QFontPrivate *d, int script) +{ + QFontDef req = d->request; + + if (req.pixelSize == -1) { + req.pixelSize = floor(((req.pointSize * d->dpi) / 72) * 100 + 0.5) / 100; + req.pixelSize = qRound(req.pixelSize); + } + if (req.pointSize < 0) + req.pointSize = req.pixelSize*72.0/d->dpi; + if (req.weight == 0) + req.weight = QFont::Normal; + if (req.stretch == 0) + req.stretch = 100; + + // Until we specifically asked not to, try looking for Multi font engine + // first, the last '1' indicates that we want Multi font engine instead + // of single ones + bool multi = !(req.styleStrategy & QFont::NoFontMerging); + QFontCache::Key key(req, script, multi ? 1 : 0); + + if (!d->engineData) + getEngineData(d, req); + + // the cached engineData could have already loaded the engine we want + if (d->engineData->engines[script]) + return; + + QFontEngine *fe = QFontCache::instance()->findEngine(key); + + // list of families to try + QStringList family_list; + + if (!req.family.isEmpty()) { + QStringList familiesForRequest = familyList(req); + + // Add primary selection + family_list << familiesForRequest.takeFirst(); + + // Fallbacks requested in font request + req.fallBackFamilies = familiesForRequest; + + // add the default family + QString defaultFamily = QGuiApplication::font().family(); + if (! family_list.contains(defaultFamily)) + family_list << defaultFamily; + + } + + // null family means find the first font matching the specified script + family_list << QString(); + + QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd(); + for (; !fe && it != end; ++it) { + req.family = *it; + + fe = QFontDatabase::findFont(script, d, req, multi); + if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) { + if (fe->ref.load() == 0) + delete fe; + + fe = 0; + } + + // No need to check requested fallback families again + req.fallBackFamilies.clear(); + } + + if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) { + for (int i = 0; i < QChar::ScriptCount; ++i) { + if (!d->engineData->engines[i]) { + d->engineData->engines[i] = fe; + fe->ref.ref(); + } + } + } else { + d->engineData->engines[script] = fe; + fe->ref.ref(); + } +} + +QString QFontDatabase::resolveFontFamilyAlias(const QString &family) +{ + return QGuiApplicationPrivate::platformIntegration()->fontDatabase()->resolveFontFamilyAlias(family); +} QT_END_NAMESPACE |