Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwindowsfontdatabase.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// Qt-Security score:critical reason:data-parser
4
6#ifndef QT_NO_FREETYPE
7# include "qwindowsfontdatabase_ft_p.h" // for default font
8#endif
10#include <QtCore/qt_windows.h>
11
12#include <QtGui/QFont>
13#include <QtGui/QGuiApplication>
14#include <QtGui/private/qtgui-config_p.h>
15
16#include <QtCore/qmath.h>
17#include <QtCore/QDebug>
18#include <QtCore/QFile>
19#include <QtCore/QtEndian>
20#include <QtCore/QStandardPaths>
21#include <QtCore/private/qduplicatetracker_p.h>
22#include <QtCore/private/qwinregistry_p.h>
23
24#include <wchar.h>
25
26#if QT_CONFIG(directwrite)
27# if QT_CONFIG(directwrite3)
28# include "qwindowsdirectwritefontdatabase_p.h"
29# endif
30# include <dwrite_2.h>
31# include <d2d1.h>
32# include "qwindowsfontenginedirectwrite_p.h"
33#endif
34
35#include <mutex>
36
37QT_BEGIN_NAMESPACE
38
39using namespace Qt::StringLiterals;
40
41#if QT_CONFIG(directwrite)
42static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
43 const QString &familyName = QString(),
44 bool isColorFont = false)
45{
46 const unsigned options = QWindowsFontDatabase::fontOptions();
47 if (Q_UNLIKELY(options & QWindowsFontDatabase::DontUseDirectWriteFonts))
48 return false;
49
50 // At some scales, GDI will misrender the MingLiU font, so we force use of
51 // DirectWrite to work around the issue.
52 if (Q_UNLIKELY(familyName.startsWith("MingLiU"_L1)))
53 return true;
54
55 if (isColorFont)
56 return (options & QWindowsFontDatabase::DontUseColorFonts) == 0;
57
58 return hintingPreference == QFont::PreferNoHinting
59 || hintingPreference == QFont::PreferVerticalHinting
60 || (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting);
61}
62#endif // !QT_NO_DIRECTWRITE
63
64/*!
65 \class QWindowsFontEngineData
66 \brief Static constant data shared by the font engines.
67 \internal
68*/
69
70QWindowsFontEngineData::QWindowsFontEngineData()
71 : fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma())
72{
73 // from qapplication_win.cpp
74 UINT result = 0;
75 if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0))
76 clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE);
77
78 const qreal gray_gamma = 2.31;
79 for (int i=0; i<256; ++i)
80 pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047));
81
82 HDC displayDC = GetDC(0);
83 hdc = CreateCompatibleDC(displayDC);
84 ReleaseDC(0, displayDC);
85}
86
87unsigned QWindowsFontDatabase::m_fontOptions = 0;
88
89void QWindowsFontDatabase::setFontOptions(unsigned options)
90{
91 m_fontOptions = options & (QWindowsFontDatabase::DontUseDirectWriteFonts |
92 QWindowsFontDatabase::DontUseColorFonts);
93}
94
95unsigned QWindowsFontDatabase::fontOptions()
96{
97 return m_fontOptions;
98}
99
100qreal QWindowsFontDatabase::fontSmoothingGamma()
101{
102 int winSmooth;
103 qreal result = 1;
104 if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0))
105 result = qreal(winSmooth) / qreal(1000.0);
106
107 // Safeguard ourselves against corrupt registry values...
108 if (result > 5 || result < 1)
109 result = qreal(1.4);
110 return result;
111}
112
113/*!
114 \class QWindowsFontDatabase
115 \brief Font database for Windows
116
117 \note The Qt 4.8 WIndows font database employed a mechanism of
118 delayed population of the database again passing a font name
119 to EnumFontFamiliesEx(), working around the fact that
120 EnumFontFamiliesEx() does not list all fonts by default.
121 This should be introduced to QPA as well?
122
123 \internal
124*/
125
126#ifndef QT_NO_DEBUG_STREAM
127QDebug operator<<(QDebug d, const QFontDef &def)
128{
129 QDebugStateSaver saver(d);
130 d.nospace();
131 d.noquote();
132 d << "QFontDef(Family=\"" << def.families.first() << '"';
133 if (!def.styleName.isEmpty())
134 d << ", stylename=" << def.styleName;
135 d << ", pointsize=" << def.pointSize << ", pixelsize=" << def.pixelSize
136 << ", styleHint=" << def.styleHint << ", weight=" << def.weight
137 << ", stretch=" << def.stretch << ", hintingPreference="
138 << def.hintingPreference << ')';
139 return d;
140}
141
142void QWindowsFontDatabase::debugFormat(QDebug &d, const LOGFONT &lf)
143{
144 d << "LOGFONT(\"" << QString::fromWCharArray(lf.lfFaceName)
145 << "\", lfWidth=" << lf.lfWidth << ", lfHeight=" << lf.lfHeight << ')';
146}
147
148QDebug operator<<(QDebug d, const LOGFONT &lf)
149{
150 QDebugStateSaver saver(d);
151 d.nospace();
152 d.noquote();
153 QWindowsFontDatabase::debugFormat(d, lf);
154 return d;
155}
156#endif // !QT_NO_DEBUG_STREAM
157
159{
160 switch (charSet) {
161 case ANSI_CHARSET:
162 case EASTEUROPE_CHARSET:
163 case BALTIC_CHARSET:
164 case TURKISH_CHARSET:
165 return QFontDatabase::Latin;
166 case GREEK_CHARSET:
167 return QFontDatabase::Greek;
168 case RUSSIAN_CHARSET:
169 return QFontDatabase::Cyrillic;
170 case HEBREW_CHARSET:
171 return QFontDatabase::Hebrew;
172 case ARABIC_CHARSET:
173 return QFontDatabase::Arabic;
174 case THAI_CHARSET:
175 return QFontDatabase::Thai;
176 case GB2312_CHARSET:
177 return QFontDatabase::SimplifiedChinese;
178 case CHINESEBIG5_CHARSET:
179 return QFontDatabase::TraditionalChinese;
180 case SHIFTJIS_CHARSET:
181 return QFontDatabase::Japanese;
182 case HANGUL_CHARSET:
183 case JOHAB_CHARSET:
184 return QFontDatabase::Korean;
185 case VIETNAMESE_CHARSET:
186 return QFontDatabase::Vietnamese;
187 case SYMBOL_CHARSET:
188 return QFontDatabase::Symbol;
189 default:
190 break;
191 }
192 return QFontDatabase::Any;
193}
194
195bool qt_localizedName(const QString &name)
196{
197 const QChar *c = name.unicode();
198 for (int i = 0; i < name.length(); ++i) {
199 if (c[i].unicode() >= 0x100)
200 return true;
201 }
202 return false;
203}
204
205namespace {
206
207static QString readName(bool unicode, const uchar *string, int length)
208{
209 QString out;
210 if (unicode) {
211 // utf16
212
213 length /= 2;
214 out.resize(length);
215 QChar *uc = out.data();
216 for (int i = 0; i < length; ++i)
217 uc[i] = qt_getUShort(string + 2*i);
218 } else {
219 // Apple Roman
220
221 out.resize(length);
222 QChar *uc = out.data();
223 for (int i = 0; i < length; ++i)
224 uc[i] = QLatin1Char(char(string[i]));
225 }
226 return out;
227}
228
229enum FieldTypeValue {
230 FamilyId = 1,
231 StyleId = 2,
232 PreferredFamilyId = 16,
233 PreferredStyleId = 17,
234};
235
236enum PlatformFieldValue {
237 PlatformId_Unicode = 0,
238 PlatformId_Apple = 1,
239 PlatformId_Microsoft = 3
240};
241
242QFontNames qt_getCanonicalFontNames(const uchar *table, quint32 bytes)
243{
244 QFontNames out;
245 const int NameRecordSize = 12;
246 const int MS_LangIdEnglish = 0x009;
247
248 // get the name table
249 quint16 count;
250 quint16 string_offset;
251 const unsigned char *names;
252
253 if (bytes < 8)
254 return out;
255
256 if (qt_getUShort(table) != 0)
257 return out;
258
259 count = qt_getUShort(table + 2);
260 string_offset = qt_getUShort(table + 4);
261 names = table + 6;
262
263 if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset)
264 return out;
265
266 enum PlatformIdType {
267 NotFound = 0,
268 Unicode = 1,
269 Apple = 2,
270 Microsoft = 3
271 };
272
273 PlatformIdType idStatus[4] = { NotFound, NotFound, NotFound, NotFound };
274 int ids[4] = { -1, -1, -1, -1 };
275
276 for (int i = 0; i < count; ++i) {
277 // search for the correct name entries
278
279 quint16 platform_id = qt_getUShort(names + i*NameRecordSize);
280 quint16 encoding_id = qt_getUShort(names + 2 + i*NameRecordSize);
281 quint16 language_id = qt_getUShort(names + 4 + i*NameRecordSize);
282 quint16 name_id = qt_getUShort(names + 6 + i*NameRecordSize);
283
284 PlatformIdType *idType = nullptr;
285 int *id = nullptr;
286
287 switch (name_id) {
288 case FamilyId:
289 idType = &idStatus[0];
290 id = &ids[0];
291 break;
292 case StyleId:
293 idType = &idStatus[1];
294 id = &ids[1];
295 break;
296 case PreferredFamilyId:
297 idType = &idStatus[2];
298 id = &ids[2];
299 break;
300 case PreferredStyleId:
301 idType = &idStatus[3];
302 id = &ids[3];
303 break;
304 default:
305 continue;
306 }
307
308 quint16 length = qt_getUShort(names + 8 + i*NameRecordSize);
309 quint16 offset = qt_getUShort(names + 10 + i*NameRecordSize);
310 if (DWORD(string_offset + offset + length) > bytes)
311 continue;
312
313 if ((platform_id == PlatformId_Microsoft
314 && (encoding_id == 0 || encoding_id == 1))
315 && ((language_id & 0x3ff) == MS_LangIdEnglish
316 || *idType < Microsoft)) {
317 *id = i;
318 *idType = Microsoft;
319 }
320 // not sure if encoding id 4 for Unicode is utf16 or ucs4...
321 else if (platform_id == PlatformId_Unicode && encoding_id < 4 && *idType < Unicode) {
322 *id = i;
323 *idType = Unicode;
324 }
325 else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0 && *idType < Apple) {
326 *id = i;
327 *idType = Apple;
328 }
329 }
330
331 QString strings[4];
332 for (int i = 0; i < 4; ++i) {
333 if (idStatus[i] == NotFound)
334 continue;
335 int id = ids[i];
336 quint16 length = qt_getUShort(names + 8 + id * NameRecordSize);
337 quint16 offset = qt_getUShort(names + 10 + id * NameRecordSize);
338 const unsigned char *string = table + string_offset + offset;
339 strings[i] = readName(idStatus[i] != Apple, string, length);
340 }
341
342 out.name = strings[0];
343 out.style = strings[1];
344 out.preferredName = strings[2];
345 out.preferredStyle = strings[3];
346 return out;
347}
348
349} // namespace
350
351QString qt_getEnglishName(const QString &familyName, bool includeStyle)
352{
353 QString i18n_name;
354 QString faceName = familyName;
355 faceName.truncate(LF_FACESIZE - 1);
356
357 HDC hdc = GetDC( 0 );
358 LOGFONT lf;
359 memset(&lf, 0, sizeof(LOGFONT));
360 faceName.toWCharArray(lf.lfFaceName);
361 lf.lfFaceName[faceName.size()] = 0;
362 lf.lfCharSet = DEFAULT_CHARSET;
363 HFONT hfont = CreateFontIndirect(&lf);
364
365 if (!hfont) {
366 ReleaseDC(0, hdc);
367 return QString();
368 }
369
370 HGDIOBJ oldobj = SelectObject( hdc, hfont );
371
372 const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
373
374 // get the name table
375 unsigned char *table = 0;
376
377 DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 );
378 if ( bytes == GDI_ERROR ) {
379 // ### Unused variable
380 // int err = GetLastError();
381 goto error;
382 }
383
384 table = new unsigned char[bytes];
385 GetFontData(hdc, name_tag, 0, table, bytes);
386 if ( bytes == GDI_ERROR )
387 goto error;
388
389 {
390 const QFontNames names = qt_getCanonicalFontNames(table, bytes);
391 i18n_name = names.name;
392 if (includeStyle)
393 i18n_name += u' ' + names.style;
394 }
395error:
396 delete [] table;
397 SelectObject( hdc, oldobj );
398 DeleteObject( hfont );
399 ReleaseDC( 0, hdc );
400
401 //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data());
402 return i18n_name;
403}
404
405// Note this duplicates parts of qt_getEnglishName, we should try to unify the two functions.
407{
408 QFontNames fontNames;
409 HDC hdc = GetDC(0);
410 HFONT hfont = CreateFontIndirect(&lf);
411
412 if (!hfont) {
413 ReleaseDC(0, hdc);
414 return fontNames;
415 }
416
417 HGDIOBJ oldobj = SelectObject(hdc, hfont);
418
419 // get the name table
420 QByteArray table;
421 const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
422 DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0);
423 if (bytes != GDI_ERROR) {
424 table.resize(bytes);
425
426 if (GetFontData(hdc, name_tag, 0, table.data(), bytes) != GDI_ERROR)
427 fontNames = qt_getCanonicalFontNames(reinterpret_cast<const uchar*>(table.constData()), bytes);
428 }
429
430 SelectObject(hdc, oldobj);
431 DeleteObject(hfont);
432 ReleaseDC(0, hdc);
433
434 return fontNames;
435}
436
437namespace {
438 struct StoreFontPayload {
439 StoreFontPayload(const QString &family,
440 QWindowsFontDatabase *fontDatabase)
441 : populatedFontFamily(family)
442 , windowsFontDatabase(fontDatabase)
443 {}
444
445 QString populatedFontFamily;
446 QDuplicateTracker<FontAndStyle> foundFontAndStyles;
447 QWindowsFontDatabase *windowsFontDatabase;
448 };
449}
450
451static bool addFontToDatabase(QString familyName,
452 QString styleName,
453 const LOGFONT &logFont,
454 const TEXTMETRIC *textmetric,
455 const FONTSIGNATURE *signature,
456 int type,
457 StoreFontPayload *sfp)
458{
459 // the "@family" fonts are just the same as "family". Ignore them.
460 if (familyName.isEmpty() || familyName.at(0) == u'@' || familyName.startsWith("WST_"_L1))
461 return false;
462
463 uchar charSet = logFont.lfCharSet;
464
465 static const int SMOOTH_SCALABLE = 0xffff;
466 const QString foundryName; // No such concept.
467 const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH);
468 const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE);
469 const bool unreliableTextMetrics = type == 0;
470 const bool scalable = (textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE))
471 && !unreliableTextMetrics;
472 const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight;
473 const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal;
474 const bool antialias = false;
475 const QFont::Weight weight = static_cast<QFont::Weight>(textmetric->tmWeight);
476 const QFont::Stretch stretch = QFont::Unstretched;
477
478#ifndef QT_NO_DEBUG_OUTPUT
479 if (lcQpaFonts().isDebugEnabled()) {
480 QString message;
481 QTextStream str(&message);
482 str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf;
483 if (type & DEVICE_FONTTYPE)
484 str << " DEVICE";
485 if (type & RASTER_FONTTYPE)
486 str << " RASTER";
487 if (type & TRUETYPE_FONTTYPE)
488 str << " TRUETYPE";
489 str << " scalable=" << scalable << " Size=" << size
490 << " Style=" << style << " Weight=" << weight
491 << " stretch=" << stretch << " styleName=" << styleName;
492 qCDebug(lcQpaFonts) << message;
493 }
494#endif
495 QString englishName;
496 QString faceName;
497
498 QString subFamilyName;
499 QString subFamilyStyle;
500 // Look-up names registered in the font
501 QFontNames canonicalNames = qt_getCanonicalFontNames(logFont);
502 if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty())
503 englishName = canonicalNames.name;
504 if (!canonicalNames.preferredName.isEmpty()) {
505 subFamilyName = familyName;
506 subFamilyStyle = styleName;
507 faceName = familyName; // Remember the original name for later lookups
508 familyName = canonicalNames.preferredName;
509 // Preferred style / typographic subfamily name:
510 // "If it is absent, then name ID 2 is considered to be the typographic subfamily name."
511 // From: https://docs.microsoft.com/en-us/windows/win32/directwrite/opentype-variable-fonts
512 // Name ID 2 is already stored in the styleName variable. Furthermore, for variable fonts,
513 // styleName holds the variation instance name, which should be used over name ID 2.
514 if (!canonicalNames.preferredStyle.isEmpty())
515 styleName = canonicalNames.preferredStyle;
516 }
517
518 QSupportedWritingSystems writingSystems;
519 if (type & TRUETYPE_FONTTYPE) {
520 Q_ASSERT(signature);
521 quint32 unicodeRange[4] = {
522 signature->fsUsb[0], signature->fsUsb[1],
523 signature->fsUsb[2], signature->fsUsb[3]
524 };
525 quint32 codePageRange[2] = {
526 signature->fsCsb[0], signature->fsCsb[1]
527 };
528 writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
529 // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
530 // the symbol for Baht, and Windows thus reports that it supports the Thai script.
531 // Since it's the default UI font on this platform, most widgets will be unable to
532 // display Thai text by default. As a temporary work around, we special case Segoe UI
533 // and remove the Thai script from its list of supported writing systems.
534 if (writingSystems.supported(QFontDatabase::Thai) &&
535 familyName == "Segoe UI"_L1)
536 writingSystems.setSupported(QFontDatabase::Thai, false);
537 } else {
538 const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet);
539 if (ws != QFontDatabase::Any)
540 writingSystems.setSupported(ws);
541 }
542
543 const bool wasPopulated = QPlatformFontDatabase::isFamilyPopulated(familyName);
544 QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight,
545 style, stretch, antialias, scalable, size, fixed, false, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
546
547
548 // add fonts windows can generate for us:
549 if (weight <= QFont::DemiBold && styleName.isEmpty())
550 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
551 style, stretch, antialias, scalable, size, fixed, false, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
552 if (style != QFont::StyleItalic && styleName.isEmpty())
553 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight,
554 QFont::StyleItalic, stretch, antialias, scalable, size, fixed, false, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
555 if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty())
556 QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
557 QFont::StyleItalic, stretch, antialias, scalable, size, fixed, false, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
558
559 // We came here from populating a different font family, so we have
560 // to ensure the entire typographic family is populated before we
561 // mark it as such inside registerFont()
562 if (!subFamilyName.isEmpty()
563 && familyName != subFamilyName
564 && sfp->populatedFontFamily != familyName
565 && !wasPopulated) {
566 sfp->windowsFontDatabase->populateFamily(familyName);
567 }
568
569 if (!subFamilyName.isEmpty() && familyName != subFamilyName) {
570 QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight,
571 style, stretch, antialias, scalable, size, fixed, false, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
572 }
573
574 if (!englishName.isEmpty() && englishName != familyName)
575 QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName);
576
577 return true;
578}
579
580static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
581 DWORD type, LPARAM lparam)
582{
583 const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
584 const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName);
585 const QString styleName = QString::fromWCharArray(f->elfStyle);
586
587 // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according
588 // to the documentation is identical to a TEXTMETRIC except for the last four
589 // members, which we don't use anyway
590 const FONTSIGNATURE *signature = nullptr;
591 StoreFontPayload *sfp = reinterpret_cast<StoreFontPayload *>(lparam);
592 Q_ASSERT(sfp != nullptr);
593 if (type & TRUETYPE_FONTTYPE) {
594 signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig;
595 // We get a callback for each script-type supported, but we register them all
596 // at once using the signature, so we only need one call to addFontToDatabase().
597 if (sfp->foundFontAndStyles.hasSeen({familyName, styleName}))
598 return 1;
599 }
600 addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp);
601
602 // keep on enumerating
603 return 1;
604}
605
606bool QWindowsFontDatabase::populateFamilyAliases(const QString &missingFamily)
607{
608 Q_UNUSED(missingFamily);
609
610 if (m_hasPopulatedAliases)
611 return false;
612
613 QStringList families = QFontDatabase::families();
614 for (const QString &family : families)
615 populateFamily(family);
616 m_hasPopulatedAliases = true;
617
618 return true;
619}
620
621void QWindowsFontDatabase::populateFamily(const QString &familyName)
622{
623 qCDebug(lcQpaFonts) << familyName;
624 if (familyName.size() >= LF_FACESIZE) { // Field length of LOGFONT::lfFaceName
625 qCDebug(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\'';
626 return;
627 }
628 HDC dummy = GetDC(0);
629 LOGFONT lf;
630 lf.lfCharSet = DEFAULT_CHARSET;
631 familyName.toWCharArray(lf.lfFaceName);
632 lf.lfFaceName[familyName.size()] = 0;
633 lf.lfPitchAndFamily = 0;
634 StoreFontPayload sfp(familyName, this);
635 EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast<intptr_t>(&sfp), 0);
636 ReleaseDC(0, dummy);
637}
638
639static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric,
640 DWORD, LPARAM)
641{
642 // the "@family" fonts are just the same as "family". Ignore them.
643 const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
644 const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
645 if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
646 const QString faceName = QString::fromWCharArray(faceNameW);
647 QPlatformFontDatabase::registerFontFamily(faceName);
648 // Register current font's english name as alias
649 const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE);
650 if (ttf && qt_localizedName(faceName)) {
651 const QString englishName = qt_getEnglishName(faceName);
652 if (!englishName.isEmpty())
653 QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName);
654 }
655 }
656 return 1; // continue
657}
658
659namespace {
660
661QString resolveFontPath(const QString &fontPath)
662{
663 if (fontPath.isEmpty())
664 return QString();
665
666 if (QFile::exists(fontPath))
667 return fontPath;
668
669 // resolve the path relatively to Windows Fonts directory
670 return QStandardPaths::locate(QStandardPaths::FontsLocation, fontPath);
671}
672
673}
674
675void QWindowsFontDatabase::addDefaultEUDCFont()
676{
677 const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)")
678 .stringValue(L"SystemDefaultEUDCFont");
679 if (path.isEmpty()) {
680 qCDebug(lcQpaFonts) << "There's no default EUDC font specified";
681 return;
682 }
683
684 const QString absolutePath = resolveFontPath(path);
685 if (absolutePath.isEmpty()) {
686 qCDebug(lcQpaFonts) << "Unable to locate default EUDC font:" << path;
687 return;
688 }
689
690 QFile file(absolutePath);
691 if (!file.open(QIODevice::ReadOnly)) {
692 qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << absolutePath;
693 return;
694 }
695
696 m_eudcFonts = addApplicationFont(file.readAll(), absolutePath);
697}
698
699void QWindowsFontDatabase::populateFontDatabase()
700{
701 HDC dummy = GetDC(0);
702 LOGFONT lf;
703 lf.lfCharSet = DEFAULT_CHARSET;
704 lf.lfFaceName[0] = 0;
705 lf.lfPitchAndFamily = 0;
706 EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
707 ReleaseDC(0, dummy);
708 // Work around EnumFontFamiliesEx() not listing the system font.
709 const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst();
710 if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
711 QPlatformFontDatabase::registerFontFamily(systemDefaultFamily);
712 addDefaultEUDCFont();
713}
714
715void QWindowsFontDatabase::invalidate()
716{
717 QWindowsFontDatabaseBase::invalidate();
718 removeApplicationFonts();
719}
720
721QWindowsFontDatabase::QWindowsFontDatabase()
722{
723 // Properties accessed by QWin32PrintEngine (Qt Print Support)
724 static const int hfontMetaTypeId = qRegisterMetaType<HFONT>();
725 static const int logFontMetaTypeId = qRegisterMetaType<LOGFONT>();
726 Q_UNUSED(hfontMetaTypeId);
727 Q_UNUSED(logFontMetaTypeId);
728
729 if (lcQpaFonts().isDebugEnabled()) {
730 QSharedPointer<QWindowsFontEngineData> d = data();
731 qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: "
732 << d->clearTypeEnabled << "gamma: " << d->fontSmoothingGamma;
733 }
734}
735
736QWindowsFontDatabase::~QWindowsFontDatabase()
737{
738 removeApplicationFonts();
739}
740
741QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
742{
743 FontHandle *fontHandle = static_cast<FontHandle *>(handle);
744 const QString faceName = fontHandle->faceName.left(LF_FACESIZE - 1);
745 QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
746 defaultVerticalDPI(),
747 data());
748 qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle;
749 return fe;
750}
751
752QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
753{
754 EmbeddedFont font(fontData);
755 QFontEngine *fontEngine = 0;
756
757#if QT_CONFIG(directwrite)
758 if (!useDirectWrite(hintingPreference))
759#endif
760 {
761 GUID guid;
762 CoCreateGuid(&guid);
763
764QT_WARNING_PUSH
765QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
766 QString uniqueFamilyName = u'f'
767 + QString::number(guid.Data1, 36) + u'-'
768 + QString::number(guid.Data2, 36) + u'-'
769 + QString::number(guid.Data3, 36) + u'-'
770 + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
771QT_WARNING_POP
772
773 QString actualFontName = font.changeFamilyName(uniqueFamilyName);
774 if (actualFontName.isEmpty()) {
775 qCWarning(lcQpaFonts, "%s: Can't change family name of font", __FUNCTION__);
776 return 0;
777 }
778
779 DWORD count = 0;
780 QByteArray newFontData = font.data();
781 HANDLE fontHandle =
782 AddFontMemResourceEx(const_cast<char *>(newFontData.constData()),
783 DWORD(newFontData.size()), 0, &count);
784 if (count == 0 && fontHandle != 0) {
785 RemoveFontMemResourceEx(fontHandle);
786 fontHandle = 0;
787 }
788
789 if (fontHandle == 0) {
790 qCWarning(lcQpaFonts, "%s: AddFontMemResourceEx failed", __FUNCTION__);
791 } else {
792 QFontDef request;
793 request.families = QStringList(uniqueFamilyName);
794 request.pixelSize = pixelSize;
795 request.styleStrategy = QFont::PreferMatch;
796 request.hintingPreference = hintingPreference;
797 request.stretch = QFont::Unstretched;
798
799 fontEngine = QWindowsFontDatabase::createEngine(request, QString(),
800 defaultVerticalDPI(),
801 data());
802
803 if (fontEngine) {
804 if (request.families != fontEngine->fontDef.families) {
805 qCWarning(lcQpaFonts, "%s: Failed to load font. Got fallback instead: %s", __FUNCTION__,
806 qPrintable(fontEngine->fontDef.families.constFirst()));
807 if (fontEngine->ref.loadRelaxed() == 0)
808 delete fontEngine;
809 fontEngine = 0;
810 } else {
811 Q_ASSERT(fontEngine->ref.loadRelaxed() == 0);
812
813 // Override the generated font name
814 switch (fontEngine->type()) {
815 case QFontEngine::Win:
816 static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
817 fontEngine->fontDef.families = QStringList(actualFontName);
818 break;
819#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
820 case QFontEngine::DirectWrite:
821 static_cast<QWindowsFontEngineDirectWrite *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
822 fontEngine->fontDef.families = QStringList(actualFontName);
823 break;
824#endif // directwrite && direct2d
825
826 default:
827 Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine.");
828 }
829
830 UniqueFontData uniqueData{};
831 uniqueData.handle = fontHandle;
832 ++uniqueData.refCount;
833 {
834 const std::scoped_lock lock(m_uniqueFontDataMutex);
835 m_uniqueFontData[uniqueFamilyName] = uniqueData;
836 }
837 }
838 } else {
839 RemoveFontMemResourceEx(fontHandle);
840 }
841 }
842
843 // Get style and weight info
844 if (fontEngine != nullptr)
845 font.updateFromOS2Table(fontEngine);
846 }
847#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
848 else {
849 fontEngine = QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
850 }
851#endif // directwrite && direct2d
852
853 qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine;
854 return fontEngine;
855}
856
857static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
858{
859 QList<quint32> offsets;
860 if (fileEndSentinel - fontData < 12) {
861 qCWarning(lcQpaFonts) << "Corrupted font data detected";
862 return offsets;
863 }
864
865 const quint32 headerTag = qFromUnaligned<quint32>(fontData);
866 if (headerTag != qFromBigEndian(QFont::Tag("ttcf").value())) {
867 if (headerTag != qFromBigEndian(QFont::Tag("\0\1\0\0").value())
868 && headerTag != qFromBigEndian(QFont::Tag("OTTO").value())
869 && headerTag != qFromBigEndian(QFont::Tag("true").value())
870 && headerTag != qFromBigEndian(QFont::Tag("typ1").value())) {
871 return offsets;
872 }
873 offsets << 0;
874 return offsets;
875 }
876
877 const quint32 maximumNumFonts = 0xffff;
878 const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
879 if (numFonts > maximumNumFonts) {
880 qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting.";
881 return offsets;
882 }
883
884 if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) {
885 for (quint32 i = 0; i < numFonts; ++i)
886 offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
887 } else {
888 qCWarning(lcQpaFonts) << "Corrupted font data detected";
889 }
890
891 return offsets;
892}
893
894static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
895{
896 if (fileEndSentinel - data >= 6) {
897 const quint16 numTables = qFromBigEndian<quint16>(data + 4);
898 if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) {
899 for (quint32 i = 0; i < numTables; ++i) {
900 const quint32 offset = 12 + 16 * i;
901 if (qFromUnaligned<quint32>(data + offset) == tag) {
902 const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8);
903 if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) {
904 qCWarning(lcQpaFonts) << "Corrupted font data detected";
905 break;
906 }
907 *table = fileBegin + tableOffset;
908 *length = qFromBigEndian<quint32>(data + offset + 12);
909 if (quintptr(fileEndSentinel - *table) < *length) {
910 qCWarning(lcQpaFonts) << "Corrupted font data detected";
911 break;
912 }
913 return;
914 }
915 }
916 } else {
917 qCWarning(lcQpaFonts) << "Corrupted font data detected";
918 }
919 } else {
920 qCWarning(lcQpaFonts) << "Corrupted font data detected";
921 }
922 *table = 0;
923 *length = 0;
924 return;
925}
926
927static void getFamiliesAndSignatures(const QByteArray &fontData,
928 QList<QFontNames> *families,
929 QList<FONTSIGNATURE> *signatures,
930 QList<QFontValues> *values)
931{
932 const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
933 const uchar *dataEndSentinel = data + fontData.size();
934
935 QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
936 if (offsets.isEmpty())
937 return;
938
939 for (int i = 0; i < offsets.count(); ++i) {
940 const uchar *font = data + offsets.at(i);
941 const uchar *table;
942 quint32 length;
943 getFontTable(data, dataEndSentinel, font,
944 qFromBigEndian(QFont::Tag("name").value()),
945 &table, &length);
946 if (!table)
947 continue;
948 QFontNames names = qt_getCanonicalFontNames(table, length);
949 if (names.name.isEmpty())
950 continue;
951
952 families->append(std::move(names));
953
954 if (values || signatures) {
955 getFontTable(data, dataEndSentinel, font,
956 qFromBigEndian(QFont::Tag("OS/2").value()),
957 &table, &length);
958 }
959
960 if (values) {
961 QFontValues fontValues;
962 if (table && length >= 64) {
963 // Read in some details about the font, offset calculated based on the specification
964 fontValues.weight = qFromBigEndian<quint16>(table + 4);
965
966 quint16 fsSelection = qFromBigEndian<quint16>(table + 62);
967 fontValues.isItalic = (fsSelection & 1) != 0;
968 fontValues.isUnderlined = (fsSelection & (1 << 1)) != 0;
969 fontValues.isOverstruck = (fsSelection & (1 << 4)) != 0;
970 }
971 values->append(std::move(fontValues));
972 }
973
974 if (signatures) {
975 FONTSIGNATURE signature;
976 if (table && length >= 86) {
977 // Offsets taken from OS/2 table in the TrueType spec
978 signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
979 signature.fsUsb[1] = qFromBigEndian<quint32>(table + 46);
980 signature.fsUsb[2] = qFromBigEndian<quint32>(table + 50);
981 signature.fsUsb[3] = qFromBigEndian<quint32>(table + 54);
982
983 signature.fsCsb[0] = qFromBigEndian<quint32>(table + 78);
984 signature.fsCsb[1] = qFromBigEndian<quint32>(table + 82);
985 } else {
986 memset(&signature, 0, sizeof(signature));
987 }
988 signatures->append(signature);
989 }
990 }
991}
992
993QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
994{
995 WinApplicationFont font;
996 font.fileName = fileName;
997 QList<FONTSIGNATURE> signatures;
998 QList<QFontValues> fontValues;
999 QList<QFontNames> families;
1000 QStringList familyNames;
1001
1002 if (!fontData.isEmpty()) {
1003 getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues);
1004 if (families.isEmpty())
1005 return familyNames;
1006
1007 DWORD dummy = 0;
1008 font.handle =
1009 AddFontMemResourceEx(const_cast<char *>(fontData.constData()),
1010 DWORD(fontData.size()), 0, &dummy);
1011 if (font.handle == 0)
1012 return QStringList();
1013
1014 // Memory fonts won't show up in enumeration, so do add them the hard way.
1015 for (int j = 0; j < families.count(); ++j) {
1016 const auto &family = families.at(j);
1017 const QString &familyName = family.name;
1018 const QString &styleName = family.style;
1019 familyNames << familyName;
1020 HDC hdc = GetDC(0);
1021 LOGFONT lf;
1022 memset(&lf, 0, sizeof(LOGFONT));
1023 memcpy(lf.lfFaceName, familyName.data(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size()));
1024 lf.lfCharSet = DEFAULT_CHARSET;
1025 const QFontValues &values = fontValues.at(j);
1026 lf.lfWeight = values.weight;
1027 if (values.isItalic)
1028 lf.lfItalic = TRUE;
1029 if (values.isOverstruck)
1030 lf.lfStrikeOut = TRUE;
1031 if (values.isUnderlined)
1032 lf.lfUnderline = TRUE;
1033 HFONT hfont = CreateFontIndirect(&lf);
1034 HGDIOBJ oldobj = SelectObject(hdc, hfont);
1035
1036 if (applicationFont != nullptr) {
1037 QFontDatabasePrivate::ApplicationFont::Properties properties;
1038 properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal;
1039 properties.weight = static_cast<int>(values.weight);
1040 properties.familyName = familyName;
1041 properties.styleName = styleName;
1042
1043 applicationFont->properties.append(properties);
1044 }
1045
1046 TEXTMETRIC textMetrics;
1047 GetTextMetrics(hdc, &textMetrics);
1048
1049 StoreFontPayload sfp(familyName, this);
1050 addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j),
1051 TRUETYPE_FONTTYPE, &sfp);
1052
1053 SelectObject(hdc, oldobj);
1054 DeleteObject(hfont);
1055 ReleaseDC(0, hdc);
1056 }
1057 } else {
1058 QFile f(fileName);
1059 if (!f.open(QIODevice::ReadOnly))
1060 return QStringList();
1061 QByteArray data = f.readAll();
1062 f.close();
1063
1064
1065 getFamiliesAndSignatures(data, &families, nullptr, applicationFont != nullptr ? &fontValues : nullptr);
1066
1067 if (families.isEmpty())
1068 return QStringList();
1069
1070 if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0)
1071 return QStringList();
1072
1073 font.handle = 0;
1074
1075 // Fonts based on files are added via populate, as they will show up in font enumeration.
1076 for (int j = 0; j < families.count(); ++j) {
1077 const QString familyName = families.at(j).name;
1078 familyNames << familyName;
1079
1080 if (applicationFont != nullptr) {
1081 const QString &styleName = families.at(j).style;
1082 const QFontValues &values = fontValues.at(j);
1083
1084 QFontDatabasePrivate::ApplicationFont::Properties properties;
1085 properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal;
1086 properties.weight = static_cast<int>(values.weight);
1087 properties.familyName = familyName;
1088 properties.styleName = styleName;
1089
1090 applicationFont->properties.append(properties);
1091 }
1092
1093 populateFamily(familyName);
1094 }
1095 }
1096
1097 m_applicationFonts << font;
1098
1099 return familyNames;
1100}
1101
1102void QWindowsFontDatabase::removeApplicationFonts()
1103{
1104 for (const WinApplicationFont &font : std::as_const(m_applicationFonts)) {
1105 if (font.handle) {
1106 RemoveFontMemResourceEx(font.handle);
1107 } else {
1108 RemoveFontResourceExW(reinterpret_cast<LPCWSTR>(font.fileName.utf16()),
1109 FR_PRIVATE, nullptr);
1110 }
1111 }
1112 m_applicationFonts.clear();
1113 m_eudcFonts.clear();
1114}
1115
1116QWindowsFontDatabase::FontHandle::FontHandle(IDWriteFontFace *face, const QString &name)
1117 : fontFace(face), faceName(name)
1118{
1119 fontFace->AddRef();
1120}
1121
1122
1123QWindowsFontDatabase::FontHandle::~FontHandle()
1124{
1125 if (fontFace != nullptr)
1126 fontFace->Release();
1127}
1128
1129void QWindowsFontDatabase::releaseHandle(void *handle)
1130{
1131 delete static_cast<FontHandle *>(handle);
1132}
1133
1134QString QWindowsFontDatabase::fontDir() const
1135{
1136 const QString result = QPlatformFontDatabase::fontDir();
1137 qCDebug(lcQpaFonts) << __FUNCTION__ << result;
1138 return result;
1139}
1140
1141bool QWindowsFontDatabase::fontsAlwaysScalable() const
1142{
1143 return false;
1144}
1145
1146void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont)
1147{
1148 const std::scoped_lock lock(m_uniqueFontDataMutex);
1149 const auto it = m_uniqueFontData.find(uniqueFont);
1150 if (it != m_uniqueFontData.end()) {
1151 if (--it->refCount == 0) {
1152 RemoveFontMemResourceEx(it->handle);
1153 m_uniqueFontData.erase(it);
1154 }
1155 }
1156}
1157
1158void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
1159{
1160 const std::scoped_lock lock(m_uniqueFontDataMutex);
1161 const auto it = m_uniqueFontData.find(uniqueFont);
1162 if (it != m_uniqueFontData.end())
1163 ++it->refCount;
1164}
1165
1166QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family,
1167 QFont::Style style,
1168 QFont::StyleHint styleHint,
1169 QFontDatabasePrivate::ExtendedScript script) const
1170{
1171 QStringList result;
1172 result.append(QWindowsFontDatabaseBase::familiesForScript(script));
1173 result.append(familyForStyleHint(styleHint));
1174 result.append(m_eudcFonts);
1175 result.append(extraTryFontsForFamily(family));
1176 result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script));
1177
1178 qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
1179 << script << result;
1180 return result;
1181}
1182
1183
1184QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const QString &faceName,
1185 int dpi,
1186 const QSharedPointer<QWindowsFontEngineData> &data)
1187{
1188 QFontEngine *fe = nullptr;
1189
1190 LOGFONT lf = fontDefToLOGFONT(request, faceName);
1191 const bool preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY;
1192
1193 if (request.stretch != 100) {
1194 HFONT hfont = CreateFontIndirect(&lf);
1195 if (!hfont) {
1196 qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__);
1197 hfont = QWindowsFontDatabase::systemFont();
1198 }
1199
1200 HGDIOBJ oldObj = SelectObject(data->hdc, hfont);
1201 TEXTMETRIC tm;
1202 if (!GetTextMetrics(data->hdc, &tm))
1203 qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__);
1204 else
1205 lf.lfWidth = tm.tmAveCharWidth * request.stretch / 100;
1206 SelectObject(data->hdc, oldObj);
1207
1208 DeleteObject(hfont);
1209 }
1210
1211#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
1212 if (data->directWriteFactory != nullptr) {
1213 const QString fam = QString::fromWCharArray(lf.lfFaceName);
1214 const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
1215 if (nameSubstitute != fam) {
1216 const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
1217 memcpy(lf.lfFaceName, nameSubstitute.data(), nameSubstituteLength * sizeof(wchar_t));
1218 lf.lfFaceName[nameSubstituteLength] = 0;
1219 }
1220
1221 HFONT hfont = CreateFontIndirect(&lf);
1222 if (!hfont) {
1223 qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__);
1224 } else {
1225 HGDIOBJ oldFont = SelectObject(data->hdc, hfont);
1226
1227 const QFont::HintingPreference hintingPreference =
1228 static_cast<QFont::HintingPreference>(request.hintingPreference);
1229 bool useDw = useDirectWrite(hintingPreference, fam);
1230
1231 IDWriteFontFace *directWriteFontFace = NULL;
1232 HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace);
1233 if (SUCCEEDED(hr)) {
1234 bool isColorFont = false;
1235 bool needsSimulation = false;
1236#if QT_CONFIG(direct2d)
1237 IDWriteFontFace2 *directWriteFontFace2 = nullptr;
1238 if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2),
1239 reinterpret_cast<void **>(&directWriteFontFace2)))) {
1240 if (directWriteFontFace2->IsColorFont())
1241 isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0;
1242
1243 needsSimulation = directWriteFontFace2->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE;
1244
1245 directWriteFontFace2->Release();
1246 }
1247#endif // direct2d
1248 useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont) || needsSimulation;
1249 qCDebug(lcQpaFonts)
1250 << __FUNCTION__ << request.families.first() << request.pointSize << "pt"
1251 << "hintingPreference=" << hintingPreference << "color=" << isColorFont
1252 << dpi << "dpi"
1253 << "useDirectWrite=" << useDw;
1254 if (useDw) {
1255 QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
1256 request.pixelSize,
1257 data);
1258
1259 wchar_t n[64];
1260 GetTextFace(data->hdc, 64, n);
1261
1262 QFontDef fontDef = request;
1263 fontDef.families = QStringList(QString::fromWCharArray(n));
1264 fedw->initFontInfo(fontDef, dpi);
1265 fe = fedw;
1266 }
1267 directWriteFontFace->Release();
1268 } else if (useDw) {
1269 const QString errorString = qt_error_string(int(hr));
1270 qCWarning(lcQpaFonts).noquote().nospace() << "DirectWrite: CreateFontFaceFromHDC() failed ("
1271 << errorString << ") for " << request << ' ' << lf << " dpi=" << dpi;
1272 }
1273
1274 SelectObject(data->hdc, oldFont);
1275 DeleteObject(hfont);
1276 }
1277 }
1278#endif // directwrite direct2d
1279
1280 if (!fe) {
1281 QWindowsFontEngine *few = new QWindowsFontEngine(request.families.first(), lf, data);
1282 if (preferClearTypeAA)
1283 few->glyphFormat = QFontEngine::Format_A32;
1284 few->initFontInfo(request, dpi);
1285 fe = few;
1286 }
1287
1288 return fe;
1289}
1290
1291bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const
1292{
1293 return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family);
1294}
1295
1296bool QWindowsFontDatabase::supportsColrv0Fonts() const
1297{
1298 return true;
1299}
1300
1301QT_END_NAMESPACE
static QList< quint32 > getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
static QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet)
static bool addFontToDatabase(QString familyName, QString styleName, const LOGFONT &logFont, const TEXTMETRIC *textmetric, const FONTSIGNATURE *signature, int type, StoreFontPayload *sfp)
static void getFamiliesAndSignatures(const QByteArray &fontData, QList< QFontNames > *families, QList< FONTSIGNATURE > *signatures, QList< QFontValues > *values)
QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
QString qt_getEnglishName(const QString &familyName, bool includeStyle=false)
bool qt_localizedName(const QString &name)