Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qwindowsfontdatabase_ft.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <QtGui/private/qfontengine_ft_p.h>
8
9#include <ft2build.h>
10#include FT_TRUETYPE_TABLES_H
11
12#include <QtCore/QDir>
13#include <QtCore/QDirIterator>
14#include <QtCore/QSettings>
15#if QT_CONFIG(regularexpression)
16#include <QtCore/QRegularExpression>
17#endif
18#include <QtCore/private/qduplicatetracker_p.h>
19
20#include <QtGui/QGuiApplication>
21#include <QtGui/QFontDatabase>
22
23#include <wchar.h>
24
26
27using namespace Qt::StringLiterals;
28
30{
31 switch (charSet) {
32 case ANSI_CHARSET:
33 case EASTEUROPE_CHARSET:
34 case BALTIC_CHARSET:
35 case TURKISH_CHARSET:
37 case GREEK_CHARSET:
39 case RUSSIAN_CHARSET:
41 case HEBREW_CHARSET:
43 case ARABIC_CHARSET:
45 case THAI_CHARSET:
47 case GB2312_CHARSET:
49 case CHINESEBIG5_CHARSET:
51 case SHIFTJIS_CHARSET:
53 case HANGUL_CHARSET:
54 case JOHAB_CHARSET:
56 case VIETNAMESE_CHARSET:
58 case SYMBOL_CHARSET:
60 default:
61 break;
62 }
63 return QFontDatabase::Any;
64}
65
67{
68 FontFile *fontFile = new FontFile;
69 fontFile->fileName = fileName;
70 fontFile->indexValue = index;
71 return fontFile;
72}
73
74namespace {
75struct FontKey
76{
78 QStringList fontNames;
79};
80} // namespace
81
82using FontKeys = QList<FontKey>;
83
85{
86 static FontKeys result;
87 if (result.isEmpty()) {
88 const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
89 QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") };
90 for (const auto &key : keys) {
91 const QSettings fontRegistry(key, QSettings::NativeFormat);
92 const QStringList allKeys = fontRegistry.allKeys();
93 const QString trueType = QStringLiteral("(TrueType)");
94#if QT_CONFIG(regularexpression)
95 const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+"));
96 Q_ASSERT(sizeListMatch.isValid());
97#endif
98 const int size = allKeys.size();
99 result.reserve(result.size() + size);
100 for (int i = 0; i < size; ++i) {
101 FontKey fontKey;
102 const QString &registryFontKey = allKeys.at(i);
103 fontKey.fileName = fontRegistry.value(registryFontKey).toString();
104 QString realKey = registryFontKey;
105 realKey.remove(trueType);
106#if QT_CONFIG(regularexpression)
107 realKey.remove(sizeListMatch);
108#endif
109 const auto fontNames = QStringView(realKey).trimmed().split(u'&');
110 fontKey.fontNames.reserve(fontNames.size());
111 for (const auto &fontName : fontNames)
112 fontKey.fontNames.append(fontName.trimmed().toString());
113 result.append(fontKey);
114 }
115 }
116 }
117 return result;
118}
119
120static const FontKey *findFontKey(const QString &name, int *indexIn = nullptr)
121{
122 const FontKeys &keys = fontKeys();
123 for (auto it = keys.constBegin(), cend = keys.constEnd(); it != cend; ++it) {
124 const int index = it->fontNames.indexOf(name);
125 if (index >= 0) {
126 if (indexIn)
127 *indexIn = index;
128 return &(*it);
129 }
130 }
131 if (indexIn)
132 *indexIn = -1;
133 return nullptr;
134}
135
136static bool addFontToDatabase(QString familyName,
137 QString styleName,
138 const QString &fullName,
139 const LOGFONT &logFont,
140 const TEXTMETRIC *textmetric,
141 const FONTSIGNATURE *signature,
142 int type)
143{
144 // the "@family" fonts are just the same as "family". Ignore them.
145 if (familyName.isEmpty() || familyName.at(0) == u'@' || familyName.startsWith("WST_"_L1))
146 return false;
147
148 uchar charSet = logFont.lfCharSet;
149
150 static const int SMOOTH_SCALABLE = 0xffff;
151 const QString foundryName; // No such concept.
152 const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH);
153 const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE);
154 const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
155 const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight;
156 const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal;
157 const bool antialias = false;
158 const QFont::Weight weight = static_cast<QFont::Weight>(textmetric->tmWeight);
159 const QFont::Stretch stretch = QFont::Unstretched;
160
161#ifndef QT_NO_DEBUG_STREAM
162 if (lcQpaFonts().isDebugEnabled()) {
165 str << __FUNCTION__ << ' ' << familyName << "::" << fullName << ' ' << charSet << " TTF=" << ttf;
166 if (type & DEVICE_FONTTYPE)
167 str << " DEVICE";
168 if (type & RASTER_FONTTYPE)
169 str << " RASTER";
170 if (type & TRUETYPE_FONTTYPE)
171 str << " TRUETYPE";
172 str << " scalable=" << scalable << " Size=" << size
173 << " Style=" << style << " Weight=" << weight
174 << " stretch=" << stretch;
175 qCDebug(lcQpaFonts) << message;
176 }
177#endif
178
179 QString englishName;
180 QString faceName = familyName;
181
182 QString subFamilyName;
183 QString subFamilyStyle;
184 // Look-up names registered in the font
185 QFontNames canonicalNames = qt_getCanonicalFontNames(logFont);
186 if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty())
187 englishName = canonicalNames.name;
188 if (!canonicalNames.preferredName.isEmpty()) {
189 subFamilyName = familyName;
190 subFamilyStyle = styleName;
191 familyName = canonicalNames.preferredName;
192 styleName = canonicalNames.preferredStyle;
193 }
194
195 QSupportedWritingSystems writingSystems;
196 if (type & TRUETYPE_FONTTYPE) {
197 Q_ASSERT(signature);
198 quint32 unicodeRange[4] = {
199 signature->fsUsb[0], signature->fsUsb[1],
200 signature->fsUsb[2], signature->fsUsb[3]
201 };
202 quint32 codePageRange[2] = {
203 signature->fsCsb[0], signature->fsCsb[1]
204 };
205 writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
206 // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
207 // the symbol for Baht, and Windows thus reports that it supports the Thai script.
208 // Since it's the default UI font on this platform, most widgets will be unable to
209 // display Thai text by default. As a temporary work around, we special case Segoe UI
210 // and remove the Thai script from its list of supported writing systems.
211 if (writingSystems.supported(QFontDatabase::Thai) && faceName == "Segoe UI"_L1)
212 writingSystems.setSupported(QFontDatabase::Thai, false);
213 } else {
215 if (ws != QFontDatabase::Any)
216 writingSystems.setSupported(ws);
217 }
218
219 int index = 0;
220 const FontKey *key = findFontKey(fullName, &index);
221 if (!key) {
222 // On non-English locales, the styles of the font may be localized in enumeration, but
223 // not in the registry.
225 if (systemLocale.language() != QLocale::C
226 && systemLocale.language() != QLocale::English
227 && styleName != "Italic"_L1
228 && styleName != "Bold"_L1) {
230 }
231 if (!key)
232 key = findFontKey(faceName, &index);
233 if (!key && !englishName.isEmpty())
234 key = findFontKey(englishName, &index);
235 if (!key)
236 return false;
237 }
238 QString value = key->fileName;
239 if (value.isEmpty())
240 return false;
241
243 value.prepend(QFile::decodeName(qgetenv("windir") + "\\Fonts\\"));
244
245 QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch,
246 antialias, scalable, size, fixed, writingSystems, createFontFile(value, index));
247
248 // add fonts windows can generate for us:
249 if (weight <= QFont::DemiBold && styleName.isEmpty())
250 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold, style, stretch,
251 antialias, scalable, size, fixed, writingSystems, createFontFile(value, index));
252
253 if (style != QFont::StyleItalic && styleName.isEmpty())
254 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, QFont::StyleItalic, stretch,
255 antialias, scalable, size, fixed, writingSystems, createFontFile(value, index));
256
257 if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty())
259 antialias, scalable, size, fixed, writingSystems, createFontFile(value, index));
260
261 if (!subFamilyName.isEmpty() && familyName != subFamilyName) {
262 QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight,
263 style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index));
264 }
265
266 if (!englishName.isEmpty() && englishName != familyName)
268
269 return true;
270}
271
272static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
273 DWORD type, LPARAM lparam)
274{
275 const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
276 const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
277 const QString styleName = QString::fromWCharArray(f->elfStyle);
278 const QString fullName = QString::fromWCharArray(f->elfFullName);
279
280 // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according
281 // to the documentation is identical to a TEXTMETRIC except for the last four
282 // members, which we don't use anyway
283 const FONTSIGNATURE *signature = nullptr;
284 if (type & TRUETYPE_FONTTYPE) {
285 signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig;
286 // We get a callback for each script-type supported, but we register them all
287 // at once using the signature, so we only need one call to addFontToDatabase().
288 auto foundFontAndStyles = reinterpret_cast<QDuplicateTracker<FontAndStyle> *>(lparam);
289 if (foundFontAndStyles->hasSeen({faceName, styleName}))
290 return 1;
291 }
292 addFontToDatabase(faceName, styleName, fullName, *logFont, textmetric, signature, type);
293
294 // keep on enumerating
295 return 1;
296}
297
299{
300 Q_UNUSED(missingFamily);
301
303 return false;
304
306 for (const QString &family : families)
307 populateFamily(family);
309
310 return true;
311}
312
313/*
314 \brief Populates the font database using EnumFontFamiliesEx().
315
316 Normally, leaving the name empty should enumerate
317 all fonts, however, system fonts like "MS Shell Dlg 2"
318 are only found when specifying the name explicitly.
319*/
320
322{
323 qCDebug(lcQpaFonts) << familyName;
324 if (familyName.size() >= LF_FACESIZE) {
325 qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\'';
326 return;
327 }
328 HDC dummy = GetDC(0);
329 LOGFONT lf;
330 memset(&lf, 0, sizeof(LOGFONT));
331 familyName.toWCharArray(lf.lfFaceName);
332 lf.lfFaceName[familyName.size()] = 0;
333 lf.lfCharSet = DEFAULT_CHARSET;
334 lf.lfPitchAndFamily = 0;
335 QDuplicateTracker<FontAndStyle> foundFontAndStyles;
336 EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&foundFontAndStyles), 0);
337 ReleaseDC(0, dummy);
338}
339
340// Delayed population of font families
341
342static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
343 DWORD, LPARAM)
344{
345 const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
346 // the "@family" fonts are just the same as "family". Ignore them.
347 const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
348 if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
349 // Register only font families for which a font file exists for delayed population
350 const bool ttf = textmetric->tmPitchAndFamily & TMPF_TRUETYPE;
351 const QString faceName = QString::fromWCharArray(faceNameW);
352 const FontKey *key = findFontKey(faceName);
353 if (!key) {
354 key = findFontKey(QString::fromWCharArray(f->elfFullName));
355 if (!key && ttf && qt_localizedName(faceName))
356 key = findFontKey(qt_getEnglishName(faceName));
357 }
358 if (key) {
360 // Register current font's english name as alias
361 if (ttf && qt_localizedName(faceName)) {
362 const QString englishName = qt_getEnglishName(faceName);
363 if (!englishName.isEmpty())
365 }
366 }
367 }
368 return 1; // continue
369}
370
372{
373 HDC dummy = GetDC(0);
374 LOGFONT lf;
375 lf.lfCharSet = DEFAULT_CHARSET;
376 lf.lfFaceName[0] = 0;
377 lf.lfPitchAndFamily = 0;
378 EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
379 ReleaseDC(0, dummy);
380 // Work around EnumFontFamiliesEx() not listing the system font
381 const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst();
382 if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
384}
385
387{
389 qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.families.constFirst() << fe << handle;
390 return fe;
391}
392
394{
395 QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference);
396 qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe;
397 return fe;
398}
399
400QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
401{
405 result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script));
406
407 qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
408 << script << result;
409
410 return result;
411}
413{
414 const QString result = QLatin1StringView(qgetenv("windir")) + "/Fonts"_L1;//QPlatformFontDatabase::fontDir();
415 qCDebug(lcQpaFonts) << __FUNCTION__ << result;
416 return result;
417}
418
423
\inmodule QtCore
Definition qbytearray.h:57
static bool isAbsolutePath(const QString &path)
Returns true if path is absolute; returns false if it is relative.
Definition qdir.h:184
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition qfile.h:162
WritingSystem
\value Any \value Latin \value Greek \value Cyrillic \value Armenian \value Hebrew \value Arabic \val...
static QStringList families(WritingSystem writingSystem=Any)
Returns a sorted list of the available font families which support the writingSystem.
\reentrant
Definition qfont.h:22
StyleHint
Style hints are used by the \l{QFont}{font matching} algorithm to find an appropriate default family ...
Definition qfont.h:25
HintingPreference
Definition qfont.h:55
Stretch
Predefined stretch values that follow the CSS naming convention.
Definition qfont.h:83
@ Unstretched
Definition qfont.h:89
Weight
Qt uses a weighting scale from 1 to 1000 compatible with OpenType.
Definition qfont.h:63
@ DemiBold
Definition qfont.h:69
@ Bold
Definition qfont.h:70
Style
This enum describes the different styles of glyphs that are used to display text.
Definition qfont.h:76
@ StyleItalic
Definition qfont.h:78
@ StyleNormal
Definition qfont.h:77
QFontEngine * fontEngine(const QFontDef &fontDef, void *handle) override
Returns the font engine that can be used to render the font described by the font definition,...
static QLocale system()
Returns a QLocale object initialized to the system locale.
Definition qlocale.cpp:2862
@ English
Definition qlocale.h:119
static QSupportedWritingSystems writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
Helper function that determines the writing systems support by a given unicodeRange and codePageRange...
virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
Returns a list of alternative fonts for the specified family and style and script using the styleHint...
virtual QString resolveFontFamilyAlias(const QString &family) const
Resolve alias to actual font family names.
static void registerAliasToFontFamily(const QString &familyName, const QString &alias)
Helper function that register the alias for the familyName.
static void registerFontFamily(const QString &familyName)
Registers a font family with the font database.
static void registerFont(const QString &familyname, const QString &stylename, const QString &foundryname, QFont::Weight weight, QFont::Style style, QFont::Stretch stretch, bool antialiased, bool scalable, int pixelSize, bool fixedPitch, const QSupportedWritingSystems &writingSystems, void *handle)
Registers a font with the given set of attributes describing the font's foundry, family name,...
\inmodule QtCore \reentrant
\inmodule QtCore
Definition qsettings.h:30
@ NativeFormat
Definition qsettings.h:49
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
Q_CORE_EXPORT QList< QStringView > split(QStringView sep, Qt::SplitBehavior behavior=Qt::KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Splits the view into substring views wherever sep occurs, and returns the list of those string views.
Definition qstring.cpp:8249
QStringView trimmed() const noexcept
Strips leading and trailing whitespace and returns the result.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype toWCharArray(wchar_t *array) const
Definition qstring.h:1291
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1226
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3466
QString & prepend(QChar c)
Definition qstring.h:478
The QSupportedWritingSystems class is used when registering fonts with the internal Qt fontdatabase.
bool supported(QFontDatabase::WritingSystem) const
Returns true if the writing system specified by writingSystem is supported; otherwise returns false.
void setSupported(QFontDatabase::WritingSystem, bool supported=true)
Sets or clears support for the specified writingSystem based on the value given by support.
\inmodule QtCore
static QStringList extraTryFontsForFamily(const QString &family)
static QString familyForStyleHint(QFont::StyleHint styleHint)
QFontEngine * fontEngine(const QFontDef &fontDef, void *handle) override
Returns the font engine that can be used to render the font described by the font definition,...
QFont defaultFont() const override
Returns the default system font.
bool populateFamilyAliases(const QString &familyName) override
void populateFamily(const QString &familyName) override
This function is called whenever a lazily populated family, populated through registerFontFamily(),...
void populateFontDatabase() override
This function is called once at startup by Qt's internal font database.
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override
Returns a list of alternative fonts for the specified family and style and script using the styleHint...
QString fontDir() const override
Returns the directory containing the fonts used by the database.
QString str
[2]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
INT_PTR intptr_t
#define SMOOTH_SCALABLE
static const QSystemLocale * systemLocale()
Definition qlocale.cpp:746
#define qCWarning(category,...)
#define qCDebug(category,...)
GLuint64 GLenum void * handle
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLfloat GLfloat f
GLuint GLuint GLfloat weight
GLenum type
GLuint GLsizei const GLchar * message
GLenum const void * fontName
GLuint name
GLenum GLsizeiptr const void * fontData
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static void allKeys(HKEY parentHandle, const QString &rSubKey, NameSet *result, REGSAM access=0)
#define QStringLiteral(str)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
double qreal
Definition qtypes.h:187
QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
QString qt_getEnglishName(const QString &familyName, bool includeStyle)
static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, DWORD type, LPARAM lparam)
bool qt_localizedName(const QString &name)
static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, DWORD, LPARAM)
static FontKeys & fontKeys()
static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, DWORD type, LPARAM lparam)
static FontFile * createFontFile(const QString &fileName, int index)
static QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet)
static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, DWORD, LPARAM)
QList< FontKey > FontKeys
static bool addFontToDatabase(QString familyName, QString styleName, const QString &fullName, const LOGFONT &logFont, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, int type)
static const FontKey * findFontKey(const QString &name, int *indexIn=nullptr)
QStringList keys
QJSValue fullName
QStringList families
Definition qfont_p.h:54