Windows: Introduce delayed population to the FreeType font database.

Further Split apart Windows CE/Windows code paths to provide 2
implementations of populateFontDatabase():

- The desktop version uses a callback which only
  registers the font families using
  QPlatformFontDatabase::registerFontFamily() to be
  populated on demand later by populateFamily().

- The Windows CE version is unchanged.

Task-number: QTBUG-43774
Task-number: QTBUG-44647
Change-Id: Iad4ec849006a4daf86a5caea9afc89e83ccc7c63
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
This commit is contained in:
Friedemann Kleint 2015-02-11 10:15:06 +01:00
parent 26e538b6db
commit 12f684ed5f
2 changed files with 152 additions and 68 deletions

View File

@ -336,7 +336,8 @@ static bool addFontToDatabase(const QString &faceName,
uchar charSet,
const TEXTMETRIC *textmetric,
const FONTSIGNATURE *signature,
int type)
int type,
bool registerAlias)
{
// the "@family" fonts are just the same as "family". Ignore them.
if (faceName.isEmpty() || faceName.at(0) == QLatin1Char('@') || faceName.startsWith(QLatin1String("WST_")))
@ -373,7 +374,7 @@ static bool addFontToDatabase(const QString &faceName,
#endif
QString englishName;
if (ttf && localizedName(faceName))
if (registerAlias & ttf && localizedName(faceName))
englishName = getEnglishName(faceName);
QSupportedWritingSystems writingSystems;
@ -467,17 +468,127 @@ static QByteArray getFntTable(HFONT hfont, uint tag)
#endif
static int QT_WIN_CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric,
int type, LPARAM namesSetIn)
int type, LPARAM)
{
typedef QSet<QString> StringSet;
const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
const QString fullName = QString::fromWCharArray(f->elfFullName);
const uchar charSet = f->elfLogFont.lfCharSet;
#ifndef Q_OS_WINCE
const FONTSIGNATURE signature = textmetric->ntmFontSig;
#else
// 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
// anyway
addFontToDatabase(faceName, fullName, charSet, (TEXTMETRIC *)textmetric, &signature, type, false);
// keep on enumerating
return 1;
}
/*!
\brief Populate font database using EnumFontFamiliesEx().
Normally, leaving the name empty should enumerate
all fonts, however, system fonts like "MS Shell Dlg 2"
are only found when specifying the name explicitly.
*/
void QWindowsFontDatabaseFT::populateFamily(const QString &familyName)
{
qCDebug(lcQpaFonts) << familyName;
if (familyName.size() >= LF_FACESIZE) {
qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\'';
return;
}
HDC dummy = GetDC(0);
LOGFONT lf;
lf.lfCharSet = DEFAULT_CHARSET;
familyName.toWCharArray(lf.lfFaceName);
lf.lfFaceName[familyName.size()] = 0;
lf.lfPitchAndFamily = 0;
EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont, 0, 0);
ReleaseDC(0, dummy);
}
namespace {
// Context for enumerating system fonts, records whether the default font has been
// encountered, which is normally not enumerated.
struct PopulateFamiliesContext
{
PopulateFamiliesContext(const QString &f) : systemDefaultFont(f), seenSystemDefaultFont(false) {}
QString systemDefaultFont;
bool seenSystemDefaultFont;
};
} // namespace
#ifndef Q_OS_WINCE
// Delayed population of font families
static int QT_WIN_CALLBACK populateFontFamilies(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *tm, int, LPARAM lparam)
{
// the "@family" fonts are just the same as "family". Ignore them.
const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
// Register only font families for which a font file exists for delayed population
const QString faceName = QString::fromWCharArray(faceNameW);
const FontKey *key = findFontKey(faceName);
if (!key) {
key = findFontKey(QString::fromWCharArray(f->elfFullName));
if (!key && (tm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE) && localizedName(faceName))
key = findFontKey(getEnglishName(faceName));
}
if (key) {
QPlatformFontDatabase::registerFontFamily(faceName);
PopulateFamiliesContext *context = reinterpret_cast<PopulateFamiliesContext *>(lparam);
if (!context->seenSystemDefaultFont && faceName == context->systemDefaultFont)
context->seenSystemDefaultFont = true;
// Register current font's english name as alias
const bool ttf = (tm->ntmTm.tmPitchAndFamily & TMPF_TRUETYPE);
if (ttf && localizedName(faceName)) {
const QString englishName = getEnglishName(faceName);
if (!englishName.isEmpty()) {
QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName);
// Check whether the system default font name is an alias of the current font family name,
// as on Chinese Windows, where the system font "SimSun" is an alias to a font registered under a local name
if (!context->seenSystemDefaultFont && englishName == context->systemDefaultFont)
context->seenSystemDefaultFont = true;
}
}
}
}
return 1; // continue
}
void QWindowsFontDatabaseFT::populateFontDatabase()
{
HDC dummy = GetDC(0);
LOGFONT lf;
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfFaceName[0] = 0;
lf.lfPitchAndFamily = 0;
PopulateFamiliesContext context(QWindowsFontDatabase::systemDefaultFont().family());
EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)populateFontFamilies, reinterpret_cast<LPARAM>(&context), 0);
ReleaseDC(0, dummy);
// Work around EnumFontFamiliesEx() not listing the system font
if (!context.seenSystemDefaultFont)
QPlatformFontDatabase::registerFontFamily(context.systemDefaultFont);
}
#else // !Q_OS_WINCE
// Non-delayed population of fonts (Windows CE).
static int QT_WIN_CALLBACK populateFontCe(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetric,
int type, LPARAM lparam)
{
// the "@family" fonts are just the same as "family". Ignore them.
const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
const uchar charSet = f->elfLogFont.lfCharSet;
FONTSIGNATURE signature;
QByteArray table;
@ -501,14 +612,17 @@ static int QT_WIN_CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetr
} else {
memset(&signature, 0, sizeof(signature));
}
#endif
// 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
// anyway
if (addFontToDatabase(faceName, fullName,
charSet, (TEXTMETRIC *)textmetric, &signature, type)) {
reinterpret_cast<StringSet *>(namesSetIn)->insert(faceName + QStringLiteral("::") + fullName);
const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
if (addFontToDatabase(faceName, QString::fromWCharArray(f->elfFullName),
charSet, (TEXTMETRIC *)textmetric, &signature, type, true)) {
PopulateFamiliesContext *context = reinterpret_cast<PopulateFamiliesContext *>(lparam);
if (!context->seenSystemDefaultFont && faceName == context->systemDefaultFont)
context->seenSystemDefaultFont = true;
}
}
// keep on enumerating
@ -517,45 +631,19 @@ static int QT_WIN_CALLBACK storeFont(ENUMLOGFONTEX* f, NEWTEXTMETRICEX *textmetr
void QWindowsFontDatabaseFT::populateFontDatabase()
{
m_families.clear();
populate(); // Called multiple times.
// Work around EnumFontFamiliesEx() not listing the system font, see below.
const QString sysFontFamily = QGuiApplication::font().family();
if (!m_families.contains(sysFontFamily))
populate(sysFontFamily);
}
/*!
\brief Populate font database using EnumFontFamiliesEx().
Normally, leaving the name empty should enumerate
all fonts, however, system fonts like "MS Shell Dlg 2"
are only found when specifying the name explicitly.
*/
void QWindowsFontDatabaseFT::populate(const QString &family)
{
qCDebug(lcQpaFonts) << __FUNCTION__ << m_families.size() << family;
HDC dummy = GetDC(0);
LOGFONT lf;
lf.lfCharSet = DEFAULT_CHARSET;
if (family.size() >= LF_FACESIZE) {
qWarning("%s: Unable to enumerate family '%s'.",
__FUNCTION__, qPrintable(family));
return;
}
wmemcpy(lf.lfFaceName, reinterpret_cast<const wchar_t*>(family.utf16()),
family.size() + 1);
HDC dummy = GetDC(0);
lf.lfFaceName[0] = 0;
lf.lfPitchAndFamily = 0;
EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)storeFont,
(LPARAM)&m_families, 0);
PopulateFamiliesContext context(QWindowsFontDatabase::systemDefaultFont().family());
EnumFontFamiliesEx(dummy, &lf, (FONTENUMPROC)populateFontCe, reinterpret_cast<LPARAM>(&context), 0);
ReleaseDC(0, dummy);
// Work around EnumFontFamiliesEx() not listing the system font, see below.
if (!context.seenSystemDefaultFont)
populateFamily(context.systemDefaultFont);
}
#endif // Q_OS_WINCE
QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle)
{
@ -592,7 +680,7 @@ QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QF
result.append(QWindowsFontDatabase::extraTryFontsForFamily(family));
qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
<< script << result << m_families;
<< script << result;
return result;
}

View File

@ -44,6 +44,7 @@ class QWindowsFontDatabaseFT : public QBasicFontDatabase
{
public:
void populateFontDatabase();
void populateFamily(const QString &familyName) Q_DECL_OVERRIDE;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle);
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
@ -51,11 +52,6 @@ public:
QString fontDir() const Q_DECL_OVERRIDE;
QFont defaultFont() const Q_DECL_OVERRIDE;
private:
void populate(const QString &family = QString());
QSet<QString> m_families;
};
QT_END_NAMESPACE