Windows: Refactor FreeType font database.
- Split apart Windows CE/Windows code paths, moving code out of addFontToDatabase() to separate static functions. - Pass faceName/fullName as separate parameters to addFontToDatabase(). This is preparatory work for introducing the delayed font population scheme for FreeType. Task-number: QTBUG-43774 Change-Id: I3863bf847bc4024b8955d3bdb9af3cdd2abc1e5e Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
This commit is contained in:
parent
7113bb23ba
commit
54b1126805
@ -41,6 +41,7 @@
|
|||||||
#include <QtCore/QDir>
|
#include <QtCore/QDir>
|
||||||
#include <QtCore/QDirIterator>
|
#include <QtCore/QDirIterator>
|
||||||
#include <QtCore/QSettings>
|
#include <QtCore/QSettings>
|
||||||
|
#include <QtCore/QRegularExpression>
|
||||||
#include <QtGui/private/qfontengine_ft_p.h>
|
#include <QtGui/private/qfontengine_ft_p.h>
|
||||||
#include <QtGui/QGuiApplication>
|
#include <QtGui/QGuiApplication>
|
||||||
#include <QtGui/QFontDatabase>
|
#include <QtGui/QFontDatabase>
|
||||||
@ -101,7 +102,67 @@ static FontFile * createFontFile(const QString &fileName, int index)
|
|||||||
extern bool localizedName(const QString &name);
|
extern bool localizedName(const QString &name);
|
||||||
extern QString getEnglishName(const QString &familyName);
|
extern QString getEnglishName(const QString &familyName);
|
||||||
|
|
||||||
#ifdef Q_OS_WINCE
|
#ifndef Q_OS_WINCE
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct FontKey
|
||||||
|
{
|
||||||
|
QString fileName;
|
||||||
|
QStringList fontNames;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
typedef QVector<FontKey> FontKeys;
|
||||||
|
|
||||||
|
static FontKeys &fontKeys()
|
||||||
|
{
|
||||||
|
static FontKeys result;
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
const QSettings fontRegistry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
|
||||||
|
QSettings::NativeFormat);
|
||||||
|
const QStringList allKeys = fontRegistry.allKeys();
|
||||||
|
const QString trueType = QStringLiteral("(TrueType)");
|
||||||
|
const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+"));
|
||||||
|
Q_ASSERT(sizeListMatch.isValid());
|
||||||
|
const int size = allKeys.size();
|
||||||
|
result.reserve(size);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
FontKey fontKey;
|
||||||
|
const QString ®istryFontKey = allKeys.at(i);
|
||||||
|
fontKey.fileName = fontRegistry.value(registryFontKey).toString();
|
||||||
|
QString realKey = registryFontKey;
|
||||||
|
realKey.remove(trueType);
|
||||||
|
realKey.remove(sizeListMatch);
|
||||||
|
const QStringList fontNames = realKey.trimmed().split(QLatin1Char('&'));
|
||||||
|
fontKey.fontNames.reserve(fontNames.size());
|
||||||
|
foreach (const QString &fontName, fontNames)
|
||||||
|
fontKey.fontNames.append(fontName.trimmed());
|
||||||
|
result.append(fontKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const FontKey *findFontKey(const QString &name, int *indexIn = Q_NULLPTR)
|
||||||
|
{
|
||||||
|
typedef FontKeys::ConstIterator ConstIt;
|
||||||
|
|
||||||
|
const FontKeys &keys = fontKeys();
|
||||||
|
for (ConstIt it = keys.constBegin(), cend = keys.constEnd(); it != cend; ++it) {
|
||||||
|
const int index = it->fontNames.indexOf(name);
|
||||||
|
if (index >= 0) {
|
||||||
|
if (indexIn)
|
||||||
|
*indexIn = index;
|
||||||
|
return &(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (indexIn)
|
||||||
|
*indexIn = -1;
|
||||||
|
return Q_NULLPTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // Q_OS_WINCE
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
quint16 majorVersion;
|
quint16 majorVersion;
|
||||||
quint16 minorVersion;
|
quint16 minorVersion;
|
||||||
@ -220,24 +281,67 @@ static QString fontNameFromTTFile(const QString &filename)
|
|||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline QString fontSettingsOrganization() { return QStringLiteral("Qt-Project"); }
|
||||||
|
static inline QString fontSettingsApplication() { return QStringLiteral("Qtbase"); }
|
||||||
|
static inline QString fontSettingsGroup() { return QStringLiteral("CEFontCache"); }
|
||||||
|
|
||||||
|
static QString findFontFile(const QString &faceName)
|
||||||
|
{
|
||||||
|
static QHash<QString, QString> fontCache;
|
||||||
|
|
||||||
|
if (fontCache.isEmpty()) {
|
||||||
|
QSettings settings(QSettings::SystemScope, fontSettingsOrganization(), fontSettingsApplication());
|
||||||
|
settings.beginGroup(fontSettingsGroup());
|
||||||
|
foreach (const QString &fontName, settings.allKeys())
|
||||||
|
fontCache.insert(fontName, settings.value(fontName).toString());
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString value = fontCache.value(faceName);
|
||||||
|
|
||||||
|
//Fallback if we haven't cached the font yet or the font got removed/renamed iterate again over all fonts
|
||||||
|
if (value.isEmpty() || !QFile::exists(value)) {
|
||||||
|
QSettings settings(QSettings::SystemScope, fontSettingsOrganization(), fontSettingsApplication());
|
||||||
|
settings.beginGroup(fontSettingsGroup());
|
||||||
|
|
||||||
|
//empty the cache first, as it seems that it is dirty
|
||||||
|
settings.remove(QString());
|
||||||
|
|
||||||
|
QDirIterator it(QStringLiteral("/Windows"), QStringList(QStringLiteral("*.ttf")), QDir::Files | QDir::Hidden | QDir::System);
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
const QString fontFile = it.next();
|
||||||
|
const QString fontName = fontNameFromTTFile(fontFile);
|
||||||
|
if (fontName.isEmpty())
|
||||||
|
continue;
|
||||||
|
fontCache.insert(fontName, fontFile);
|
||||||
|
settings.setValue(fontName, fontFile);
|
||||||
|
|
||||||
|
if (localizedName(fontName)) {
|
||||||
|
QString englishFontName = getEnglishName(fontName);
|
||||||
|
fontCache.insert(englishFontName, fontFile);
|
||||||
|
settings.setValue(englishFontName, fontFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
value = fontCache.value(faceName);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
#endif // Q_OS_WINCE
|
#endif // Q_OS_WINCE
|
||||||
|
|
||||||
static bool addFontToDatabase(const QString &familyName, uchar charSet,
|
static bool addFontToDatabase(const QString &faceName,
|
||||||
|
const QString &fullName,
|
||||||
|
uchar charSet,
|
||||||
const TEXTMETRIC *textmetric,
|
const TEXTMETRIC *textmetric,
|
||||||
const FONTSIGNATURE *signature,
|
const FONTSIGNATURE *signature,
|
||||||
int type)
|
int type)
|
||||||
{
|
{
|
||||||
typedef QPair<QString, QStringList> FontKey;
|
|
||||||
|
|
||||||
// the "@family" fonts are just the same as "family". Ignore them.
|
// the "@family" fonts are just the same as "family". Ignore them.
|
||||||
if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_")))
|
if (faceName.isEmpty() || faceName.at(0) == QLatin1Char('@') || faceName.startsWith(QLatin1String("WST_")))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const int separatorPos = familyName.indexOf(QStringLiteral("::"));
|
|
||||||
const QString faceName =
|
|
||||||
separatorPos != -1 ? familyName.left(separatorPos) : familyName;
|
|
||||||
const QString fullName =
|
|
||||||
separatorPos != -1 ? familyName.mid(separatorPos + 2) : QString();
|
|
||||||
static const int SMOOTH_SCALABLE = 0xffff;
|
static const int SMOOTH_SCALABLE = 0xffff;
|
||||||
const QString foundryName; // No such concept.
|
const QString foundryName; // No such concept.
|
||||||
const NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
|
const NEWTEXTMETRIC *tm = (NEWTEXTMETRIC *)textmetric;
|
||||||
@ -254,7 +358,7 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet,
|
|||||||
if (QWindowsContext::verbose > 2) {
|
if (QWindowsContext::verbose > 2) {
|
||||||
QString message;
|
QString message;
|
||||||
QTextStream str(&message);
|
QTextStream str(&message);
|
||||||
str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf;
|
str << __FUNCTION__ << ' ' << faceName << "::" << fullName << ' ' << charSet << " TTF=" << ttf;
|
||||||
if (type & DEVICE_FONTTYPE)
|
if (type & DEVICE_FONTTYPE)
|
||||||
str << " DEVICE";
|
str << " DEVICE";
|
||||||
if (type & RASTER_FONTTYPE)
|
if (type & RASTER_FONTTYPE)
|
||||||
@ -297,93 +401,19 @@ static bool addFontToDatabase(const QString &familyName, uchar charSet,
|
|||||||
writingSystems.setSupported(ws);
|
writingSystems.setSupported(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
#ifndef Q_OS_WINCE
|
#ifndef Q_OS_WINCE
|
||||||
const QSettings fontRegistry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
|
const FontKey *key = findFontKey(faceName, &index);
|
||||||
QSettings::NativeFormat);
|
if (!key) {
|
||||||
|
key = findFontKey(fullName, &index);
|
||||||
static QVector<FontKey> allFonts;
|
if (!key && !englishName.isEmpty())
|
||||||
if (allFonts.isEmpty()) {
|
key = findFontKey(englishName, &index);
|
||||||
const QStringList allKeys = fontRegistry.allKeys();
|
if (!key)
|
||||||
allFonts.reserve(allKeys.size());
|
return false;
|
||||||
const QString trueType = QStringLiteral("(TrueType)");
|
|
||||||
const QRegExp sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+"));
|
|
||||||
foreach (const QString &key, allKeys) {
|
|
||||||
QString realKey = key;
|
|
||||||
realKey.remove(trueType);
|
|
||||||
realKey.remove(sizeListMatch);
|
|
||||||
QStringList fonts;
|
|
||||||
const QStringList fontNames = realKey.trimmed().split(QLatin1Char('&'));
|
|
||||||
foreach (const QString &fontName, fontNames)
|
|
||||||
fonts.push_back(fontName.trimmed());
|
|
||||||
allFonts.push_back(FontKey(key, fonts));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString value;
|
|
||||||
int index = 0;
|
|
||||||
for (int k = 0; k < allFonts.size(); ++k) {
|
|
||||||
const FontKey &fontKey = allFonts.at(k);
|
|
||||||
for (int i = 0; i < fontKey.second.length(); ++i) {
|
|
||||||
const QString &font = fontKey.second.at(i);
|
|
||||||
if (font == faceName || fullName == font || englishName == font) {
|
|
||||||
value = fontRegistry.value(fontKey.first).toString();
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!value.isEmpty())
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
QString value = key->fileName;
|
||||||
#else
|
#else
|
||||||
QString value;
|
QString value = findFontFile(faceName);
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
static QHash<QString, QString> fontCache;
|
|
||||||
|
|
||||||
if (fontCache.isEmpty()) {
|
|
||||||
QSettings settings(QSettings::SystemScope, QStringLiteral("Qt-Project"), QStringLiteral("Qtbase"));
|
|
||||||
settings.beginGroup(QStringLiteral("CEFontCache"));
|
|
||||||
|
|
||||||
foreach (const QString &fontName, settings.allKeys()) {
|
|
||||||
const QString fontFileName = settings.value(fontName).toString();
|
|
||||||
fontCache.insert(fontName, fontFileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.endGroup(); // CEFontCache
|
|
||||||
}
|
|
||||||
|
|
||||||
value = fontCache.value(faceName);
|
|
||||||
|
|
||||||
//Fallback if we haven't cached the font yet or the font got removed/renamed iterate again over all fonts
|
|
||||||
if (value.isEmpty() || !QFile::exists(value)) {
|
|
||||||
QSettings settings(QSettings::SystemScope, QStringLiteral("Qt-Project"), QStringLiteral("Qtbase"));
|
|
||||||
settings.beginGroup(QStringLiteral("CEFontCache"));
|
|
||||||
|
|
||||||
//empty the cache first, as it seems that it is dirty
|
|
||||||
foreach (const QString &fontName, settings.allKeys())
|
|
||||||
settings.remove(fontName);
|
|
||||||
|
|
||||||
QDirIterator it(QStringLiteral("/Windows"), QStringList(QStringLiteral("*.ttf")), QDir::Files | QDir::Hidden | QDir::System);
|
|
||||||
|
|
||||||
while (it.hasNext()) {
|
|
||||||
const QString fontFile = it.next();
|
|
||||||
const QString fontName = fontNameFromTTFile(fontFile);
|
|
||||||
if (fontName.isEmpty())
|
|
||||||
continue;
|
|
||||||
fontCache.insert(fontName, fontFile);
|
|
||||||
settings.setValue(fontName, fontFile);
|
|
||||||
|
|
||||||
if (localizedName(fontName)) {
|
|
||||||
QString englishFontName = getEnglishName(fontName);
|
|
||||||
fontCache.insert(englishFontName, fontFile);
|
|
||||||
settings.setValue(englishFontName, fontFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
value = fontCache.value(faceName);
|
|
||||||
|
|
||||||
settings.endGroup(); // CEFontCache
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (value.isEmpty())
|
if (value.isEmpty())
|
||||||
@ -440,9 +470,9 @@ static int QT_WIN_CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetr
|
|||||||
int type, LPARAM namesSetIn)
|
int type, LPARAM namesSetIn)
|
||||||
{
|
{
|
||||||
typedef QSet<QString> StringSet;
|
typedef QSet<QString> StringSet;
|
||||||
const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName)
|
|
||||||
+ QStringLiteral("::")
|
const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
|
||||||
+ QString::fromWCharArray(f->elfFullName);
|
const QString fullName = QString::fromWCharArray(f->elfFullName);
|
||||||
const uchar charSet = f->elfLogFont.lfCharSet;
|
const uchar charSet = f->elfLogFont.lfCharSet;
|
||||||
|
|
||||||
#ifndef Q_OS_WINCE
|
#ifndef Q_OS_WINCE
|
||||||
@ -476,8 +506,10 @@ static int QT_WIN_CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetr
|
|||||||
// NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
|
// NEWTEXTMETRICEX is a NEWTEXTMETRIC, which according to the documentation is
|
||||||
// identical to a TEXTMETRIC except for the last four members, which we don't use
|
// identical to a TEXTMETRIC except for the last four members, which we don't use
|
||||||
// anyway
|
// anyway
|
||||||
if (addFontToDatabase(familyName, charSet, (TEXTMETRIC *)textmetric, &signature, type))
|
if (addFontToDatabase(faceName, fullName,
|
||||||
reinterpret_cast<StringSet *>(namesSetIn)->insert(familyName);
|
charSet, (TEXTMETRIC *)textmetric, &signature, type)) {
|
||||||
|
reinterpret_cast<StringSet *>(namesSetIn)->insert(faceName + QStringLiteral("::") + fullName);
|
||||||
|
}
|
||||||
|
|
||||||
// keep on enumerating
|
// keep on enumerating
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user