From ba50d27e7624cdfe90124b393576020de7608332 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 7 Feb 2020 08:03:16 +0100 Subject: [PATCH] DirectWrite font db: Fix fallback fonts The implementation of this was based on a misunderstanding of the API. The GetMatchingFonts() function does not give a sorted list of fonts that can be used in place of the given family, but just requests the fonts in the family itself. Instead, we use the same implementation as in the other two font databases we have on Windows (moving the implementation to be shared). Change-Id: I6a7b73e3d8376f7d97f598db0d7b63122ad1940c Reviewed-by: Lars Knoll --- .../qwindowsdirectwritefontdatabase.cpp | 55 ++------ .../windows/qwindowsfontdatabase.cpp | 123 +----------------- .../windows/qwindowsfontdatabase_ft.cpp | 4 +- .../windows/qwindowsfontdatabase_p.h | 3 - .../windows/qwindowsfontdatabasebase.cpp | 119 +++++++++++++++++ .../windows/qwindowsfontdatabasebase_p.h | 3 + 6 files changed, 134 insertions(+), 173 deletions(-) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp index a0483c2413..e2a9dbdedd 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp @@ -39,6 +39,7 @@ #include "qwindowsdirectwritefontdatabase_p.h" #include "qwindowsfontenginedirectwrite_p.h" +#include "qwindowsfontdatabase_p.h" #include #include @@ -269,54 +270,14 @@ QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QFontDef &fontDef QStringList QWindowsDirectWriteFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { - Q_UNUSED(styleHint); - Q_UNUSED(script); + QStringList result; + result.append(familyForStyleHint(styleHint)); + result.append(extraTryFontsForFamily(family)); + result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); - wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH]; - bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0; - wchar_t englishLocale[] = L"en-us"; - - QStringList ret; - - auto it = m_populatedFonts.find(family); - IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr; - if (fontFamily != nullptr) { - IDWriteFontList *matchingFonts = nullptr; - if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR, - DWRITE_FONT_STRETCH_NORMAL, - toDirectWriteStyle(style), - &matchingFonts))) { - for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) { - IDWriteFont *font = nullptr; - if (SUCCEEDED(matchingFonts->GetFont(j, &font))) { - IDWriteFontFamily *fontFamily2; - if (SUCCEEDED(font->GetFontFamily(&fontFamily2))) { - IDWriteLocalizedStrings *names; - if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) { - QString name = localeString(names, englishLocale); - if (name.isEmpty() && hasDefaultLocale) - name = localeString(names, defaultLocale); - - if (!name.isEmpty() && m_populatedFonts.contains(name)) - ret.append(name); - - names->Release(); - } - - fontFamily2->Release(); - } - - font->Release(); - } - } - - matchingFonts->Release(); - } - } - - qDebug(lcQpaFonts) << "fallbacks for" << family << "is" << ret; - - return ret; + qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint + << script << result; + return result; } QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index cf5763fdbe..9c348c9e19 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -1080,131 +1080,12 @@ void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont) m_uniqueFontData[uniqueFont].refCount.ref(); } -// Creation functions - -static const char *other_tryFonts[] = { - "Arial", - "MS UI Gothic", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *jp_tryFonts [] = { - "MS UI Gothic", - "Arial", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *ch_CN_tryFonts [] = { - "SimSun", - "Arial", - "PMingLiU", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *ch_TW_tryFonts [] = { - "PMingLiU", - "Arial", - "SimSun", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *kr_tryFonts[] = { - "Gulim", - "Arial", - "PMingLiU", - "SimSun", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char **tryFonts = 0; - -QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family) -{ - QStringList result; - QFontDatabase db; - if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) { - if (!tryFonts) { - LANGID lid = GetUserDefaultLangID(); - switch (lid&0xff) { - case LANG_CHINESE: // Chinese - if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore - tryFonts = ch_CN_tryFonts; - else - tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau - break; - case LANG_JAPANESE: - tryFonts = jp_tryFonts; - break; - case LANG_KOREAN: - tryFonts = kr_tryFonts; - break; - default: - tryFonts = other_tryFonts; - break; - } - } - QFontDatabase db; - const QStringList families = db.families(); - const char **tf = tryFonts; - while (tf && *tf) { - // QTBUG-31689, family might be an English alias for a localized font name. - const QString family = QString::fromLatin1(*tf); - if (families.contains(family) || db.hasFamily(family)) - result << family; - ++tf; - } - } - result.append(QStringLiteral("Segoe UI Emoji")); - result.append(QStringLiteral("Segoe UI Symbol")); - return result; -} - -QString QWindowsFontDatabase::familyForStyleHint(QFont::StyleHint styleHint) -{ - switch (styleHint) { - case QFont::Times: - return QStringLiteral("Times New Roman"); - case QFont::Courier: - return QStringLiteral("Courier New"); - case QFont::Monospace: - return QStringLiteral("Courier New"); - case QFont::Cursive: - return QStringLiteral("Comic Sans MS"); - case QFont::Fantasy: - return QStringLiteral("Impact"); - case QFont::Decorative: - return QStringLiteral("Old English"); - case QFont::Helvetica: - return QStringLiteral("Arial"); - case QFont::System: - default: - break; - } - return QStringLiteral("MS Shell Dlg 2"); -} - QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { QStringList result; - result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); + result.append(familyForStyleHint(styleHint)); result.append(m_eudcFonts); - result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); + result.append(extraTryFontsForFamily(family)); result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp index 5c2742d295..b355001254 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp @@ -422,8 +422,8 @@ QFontEngine *QWindowsFontDatabaseFT::fontEngine(const QByteArray &fontData, qrea QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const { QStringList result; - result.append(QWindowsFontDatabase::familyForStyleHint(styleHint)); - result.append(QWindowsFontDatabase::extraTryFontsForFamily(family)); + result.append(QWindowsFontDatabaseBase::familyForStyleHint(styleHint)); + result.append(QWindowsFontDatabaseBase::extraTryFontsForFamily(family)); result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script)); qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h index a76fdc0810..64b80ed5b3 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h @@ -96,9 +96,6 @@ public: static qreal fontSmoothingGamma(); - static QStringList extraTryFontsForFamily(const QString &family); - static QString familyForStyleHint(QFont::StyleHint styleHint); - static void setFontOptions(unsigned options); static unsigned fontOptions(); diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp index 5b8707cdec..e6dee54d84 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp @@ -866,4 +866,123 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr return fontEngine; } +QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint) +{ + switch (styleHint) { + case QFont::Times: + return QStringLiteral("Times New Roman"); + case QFont::Courier: + return QStringLiteral("Courier New"); + case QFont::Monospace: + return QStringLiteral("Courier New"); + case QFont::Cursive: + return QStringLiteral("Comic Sans MS"); + case QFont::Fantasy: + return QStringLiteral("Impact"); + case QFont::Decorative: + return QStringLiteral("Old English"); + case QFont::Helvetica: + return QStringLiteral("Arial"); + case QFont::System: + default: + break; + } + return QStringLiteral("MS Shell Dlg 2"); +} + +// Creation functions + +static const char *other_tryFonts[] = { + "Arial", + "MS UI Gothic", + "Gulim", + "SimSun", + "PMingLiU", + "Arial Unicode MS", + 0 +}; + +static const char *jp_tryFonts [] = { + "MS UI Gothic", + "Arial", + "Gulim", + "SimSun", + "PMingLiU", + "Arial Unicode MS", + 0 +}; + +static const char *ch_CN_tryFonts [] = { + "SimSun", + "Arial", + "PMingLiU", + "Gulim", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char *ch_TW_tryFonts [] = { + "PMingLiU", + "Arial", + "SimSun", + "Gulim", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char *kr_tryFonts[] = { + "Gulim", + "Arial", + "PMingLiU", + "SimSun", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char **tryFonts = nullptr; + +QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &family) +{ + QStringList result; + QFontDatabase db; + if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) { + if (!tryFonts) { + LANGID lid = GetUserDefaultLangID(); + switch (lid&0xff) { + case LANG_CHINESE: // Chinese + if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore + tryFonts = ch_CN_tryFonts; + else + tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau + break; + case LANG_JAPANESE: + tryFonts = jp_tryFonts; + break; + case LANG_KOREAN: + tryFonts = kr_tryFonts; + break; + default: + tryFonts = other_tryFonts; + break; + } + } + QFontDatabase db; + const QStringList families = db.families(); + const char **tf = tryFonts; + while (tf && *tf) { + // QTBUG-31689, family might be an English alias for a localized font name. + const QString family = QString::fromLatin1(*tf); + if (families.contains(family) || db.hasFamily(family)) + result << family; + ++tf; + } + } + result.append(QStringLiteral("Segoe UI Emoji")); + result.append(QStringLiteral("Segoe UI Symbol")); + return result; +} + QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h index fbaa98b663..5b9db5dede 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h @@ -102,6 +102,9 @@ public: static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName); static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0); + static QString familyForStyleHint(QFont::StyleHint styleHint); + static QStringList extraTryFontsForFamily(const QString &family); + class FontTable{}; class EmbeddedFont {