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 <lars.knoll@qt.io>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2020-02-07 08:03:16 +01:00
parent 3c0cd7566c
commit ba50d27e76
6 changed files with 134 additions and 173 deletions

View File

@ -39,6 +39,7 @@
#include "qwindowsdirectwritefontdatabase_p.h"
#include "qwindowsfontenginedirectwrite_p.h"
#include "qwindowsfontdatabase_p.h"
#include <QtCore/qendian.h>
#include <QtCore/qstringbuilder.h>
@ -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)

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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
{