Fix font matching of typographic families on Windows
9204b8c31ebroke font matching on Windows. This was then attempted fixed bybcd2fa484a, but this caused an infinite recursion for some cases, so it was reverted again by9d1905da9c. The original issue was that if we populate a specific face of a family, such as "Arial Black", then the typographic/preferred name will be detected as "Arial" and this family will be set as populated=true, even though we have not yet registered any additional subfamilies. In this case, we need to call populateFamily() for the typographic family name to ensure we get Windows to enumerate all the subfamilies in that family before it sets it as populated=true. But this broke for some fonts where the font naming was unconventional. In particular, "Yu Gothic" would have its Japanese name as the typographic name, and there would be no font in the system where the old-style font family name matched the typographic name. In that case we would go into a loop where we would try populating "<Japanese font name>", Windows would translate this to "Yu Gothic", we would translate it back to "<Japanese font name>", ad infinitum. In order to avoid the infinite recursion, we add a recursion guard as well, ensuring that we never call populateFamily() for the main family we are currently populating. [ChangeLog][Windows][Fonts] Fixed a bug where it would be impossible to request different faces of a font family after a specific type face has been in use. Task-number: QTBUG-74748 Task-number: QTBUG-74983 Change-Id: Ibe6239f67c45d67ebf75947c8f231cfa177e347f Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
parent
cceeb1ee7e
commit
922d195020
|
|
@ -792,6 +792,13 @@ QString qt_resolveFontFamilyAlias(const QString &alias)
|
|||
return alias;
|
||||
}
|
||||
|
||||
bool qt_isFontFamilyPopulated(const QString &familyName)
|
||||
{
|
||||
QFontDatabasePrivate *d = privateDb();
|
||||
QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::RequestFamily);
|
||||
return f != nullptr && f->populated;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a list of alternative fonts for the specified \a family and
|
||||
\a style and \a script using the \a styleHint given.
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ void qt_registerFont(const QString &familyname, const QString &stylename,
|
|||
|
||||
void qt_registerFontFamily(const QString &familyName);
|
||||
void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias);
|
||||
bool qt_isFontFamilyPopulated(const QString &familyName);
|
||||
|
||||
/*!
|
||||
Registers the pre-rendered QPF2 font contained in the given \a dataArray.
|
||||
|
|
@ -665,6 +666,16 @@ void QPlatformFontDatabase::registerAliasToFontFamily(const QString &familyName,
|
|||
qt_registerAliasToFontFamily(familyName, alias);
|
||||
}
|
||||
|
||||
/*!
|
||||
Helper function that returns true if the font family has already been registered and populated.
|
||||
|
||||
\since 5.14
|
||||
*/
|
||||
bool QPlatformFontDatabase::isFamilyPopulated(const QString &familyName)
|
||||
{
|
||||
return qt_isFontFamilyPopulated(familyName);
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QPlatformFontDatabase
|
||||
\since 5.0
|
||||
|
|
|
|||
|
|
@ -139,6 +139,8 @@ public:
|
|||
|
||||
static void registerFontFamily(const QString &familyName);
|
||||
static void registerAliasToFontFamily(const QString &familyName, const QString &alias);
|
||||
|
||||
static bool isFamilyPopulated(const QString &familyName);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -1007,12 +1007,27 @@ static QChar *createFontFile(const QString &faceName)
|
|||
return faceNamePtr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct StoreFontPayload {
|
||||
StoreFontPayload(const QString &family,
|
||||
QWindowsFontDatabase *fontDatabase)
|
||||
: populatedFontFamily(family)
|
||||
, windowsFontDatabase(fontDatabase)
|
||||
{}
|
||||
|
||||
QString populatedFontFamily;
|
||||
QSet<QPair<QString,QString> > foundFontAndStyles;
|
||||
QWindowsFontDatabase *windowsFontDatabase;
|
||||
};
|
||||
}
|
||||
|
||||
static bool addFontToDatabase(QString familyName,
|
||||
QString styleName,
|
||||
const LOGFONT &logFont,
|
||||
const TEXTMETRIC *textmetric,
|
||||
const FONTSIGNATURE *signature,
|
||||
int type)
|
||||
int type,
|
||||
StoreFontPayload *sfp)
|
||||
{
|
||||
// the "@family" fonts are just the same as "family". Ignore them.
|
||||
if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_")))
|
||||
|
|
@ -1092,6 +1107,16 @@ static bool addFontToDatabase(QString familyName,
|
|||
writingSystems.setSupported(ws);
|
||||
}
|
||||
|
||||
// We came here from populating a different font family, so we have
|
||||
// to ensure the entire typographic family is populated before we
|
||||
// mark it as such inside registerFont()
|
||||
if (!subFamilyName.isEmpty()
|
||||
&& familyName != subFamilyName
|
||||
&& sfp->populatedFontFamily != familyName
|
||||
&& !QPlatformFontDatabase::isFamilyPopulated(familyName)) {
|
||||
sfp->windowsFontDatabase->populateFamily(familyName);
|
||||
}
|
||||
|
||||
QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight,
|
||||
style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
|
||||
|
||||
|
|
@ -1128,17 +1153,18 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t
|
|||
// to the documentation is identical to a TEXTMETRIC except for the last four
|
||||
// members, which we don't use anyway
|
||||
const FONTSIGNATURE *signature = nullptr;
|
||||
StoreFontPayload *sfp = reinterpret_cast<StoreFontPayload *>(lparam);
|
||||
Q_ASSERT(sfp != nullptr);
|
||||
if (type & TRUETYPE_FONTTYPE) {
|
||||
signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig;
|
||||
// We get a callback for each script-type supported, but we register them all
|
||||
// at once using the signature, so we only need one call to addFontToDatabase().
|
||||
QSet<QPair<QString,QString>> *foundFontAndStyles = reinterpret_cast<QSet<QPair<QString,QString>> *>(lparam);
|
||||
QPair<QString,QString> fontAndStyle(familyName, styleName);
|
||||
if (foundFontAndStyles->contains(fontAndStyle))
|
||||
if (sfp->foundFontAndStyles.contains(fontAndStyle))
|
||||
return 1;
|
||||
foundFontAndStyles->insert(fontAndStyle);
|
||||
sfp->foundFontAndStyles.insert(fontAndStyle);
|
||||
}
|
||||
addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type);
|
||||
addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp);
|
||||
|
||||
// keep on enumerating
|
||||
return 1;
|
||||
|
|
@ -1157,8 +1183,8 @@ void QWindowsFontDatabase::populateFamily(const QString &familyName)
|
|||
familyName.toWCharArray(lf.lfFaceName);
|
||||
lf.lfFaceName[familyName.size()] = 0;
|
||||
lf.lfPitchAndFamily = 0;
|
||||
QSet<QPair<QString,QString>> foundFontAndStyles;
|
||||
EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&foundFontAndStyles), 0);
|
||||
StoreFontPayload sfp(familyName, this);
|
||||
EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&sfp), 0);
|
||||
ReleaseDC(0, dummy);
|
||||
}
|
||||
|
||||
|
|
@ -1598,8 +1624,9 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
|
|||
TEXTMETRIC textMetrics;
|
||||
GetTextMetrics(hdc, &textMetrics);
|
||||
|
||||
StoreFontPayload sfp(familyName, this);
|
||||
addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j),
|
||||
TRUETYPE_FONTTYPE);
|
||||
TRUETYPE_FONTTYPE, &sfp);
|
||||
|
||||
SelectObject(hdc, oldobj);
|
||||
DeleteObject(hfont);
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ public:
|
|||
QWindowsFontDatabase();
|
||||
~QWindowsFontDatabase() override;
|
||||
|
||||
void ensureFamilyPopulated(const QString &familyName);
|
||||
|
||||
void populateFontDatabase() override;
|
||||
void populateFamily(const QString &familyName) override;
|
||||
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
|
||||
|
|
|
|||
Loading…
Reference in New Issue