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
qwindowsdirectwritefontdatabase.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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
7
8#include <QtCore/qendian.h>
9#include <QtCore/qfile.h>
10#include <QtCore/qstringbuilder.h>
11#include <QtCore/qvarlengtharray.h>
12
13#include <dwrite_3.h>
14#include <d2d1.h>
15
17
18// Defined in gui/text/qfontdatabase.cpp
20
21template<typename T>
23 DirectWriteScope(T *res = nullptr) : m_res(res) {}
25 if (m_res != nullptr)
26 m_res->Release();
27 }
28
30 {
31 return &m_res;
32 }
33
35 {
36 return m_res;
37 }
38
39 T *operator*() {
40 return m_res;
41 }
42
43private:
44 T *m_res;
45};
46
48{
49 qCDebug(lcQpaFonts) << "Creating DirectWrite database";
50}
51
53{
54 for (auto it = m_populatedFonts.begin(); it != m_populatedFonts.end(); ++it)
55 it.value()->Release();
56}
57
58QString QWindowsDirectWriteFontDatabase::localeString(IDWriteLocalizedStrings *names,
59 wchar_t localeName[])
60{
61 uint index;
62 BOOL exists;
63 if (SUCCEEDED(names->FindLocaleName(localeName, &index, &exists)) && exists) {
65 if (SUCCEEDED(names->GetStringLength(index, &length)) && length > 0) {
66 QVarLengthArray<wchar_t> buffer(int(length) + 1);
67 if (SUCCEEDED(names->GetString(index, buffer.data(), length + 1)))
68 return QString::fromWCharArray(buffer.data());
69 }
70 }
71
72 return QString();
73}
74
75static QFont::Stretch fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch)
76{
77 switch (stretch) {
78 case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return QFont::UltraCondensed;
79 case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return QFont::ExtraCondensed;
80 case DWRITE_FONT_STRETCH_CONDENSED: return QFont::Condensed;
81 case DWRITE_FONT_STRETCH_SEMI_CONDENSED: return QFont::SemiCondensed;
82 case DWRITE_FONT_STRETCH_NORMAL: return QFont::Unstretched;
83 case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return QFont::SemiExpanded;
84 case DWRITE_FONT_STRETCH_EXPANDED: return QFont::Expanded;
85 case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return QFont::ExtraExpanded;
86 case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return QFont::UltraExpanded;
87 default: return QFont::AnyStretch;
88 }
89}
90
91static QFont::Weight fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight)
92{
93 return static_cast<QFont::Weight>(weight);
94}
95
96static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style)
97{
98 switch (style) {
99 case DWRITE_FONT_STYLE_NORMAL: return QFont::StyleNormal;
100 case DWRITE_FONT_STYLE_OBLIQUE: return QFont::StyleOblique;
101 case DWRITE_FONT_STYLE_ITALIC: return QFont::StyleItalic;
102 default: return QFont::StyleNormal;
103 }
104}
105
107{
108 auto it = m_populatedFonts.find(familyName);
109 if (it == m_populatedFonts.end() && m_populatedBitmapFonts.contains(familyName)) {
110 qCDebug(lcQpaFonts) << "Populating bitmap font" << familyName;
112 return;
113 }
114
115 IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr;
116 if (fontFamily == nullptr) {
117 qCWarning(lcQpaFonts) << "Cannot find" << familyName << "in list of fonts";
118 return;
119 }
120
121 qCDebug(lcQpaFonts) << "Populate family:" << familyName;
122
123 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
124 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
125 wchar_t englishLocale[] = L"en-us";
126
127 static const int SMOOTH_SCALABLE = 0xffff;
128 const QString foundryName; // No such concept.
129 const bool scalable = true;
130 const bool antialias = false;
131 const int size = SMOOTH_SCALABLE;
132
133 DirectWriteScope<IDWriteFontList> matchingFonts;
134 if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR,
135 DWRITE_FONT_STRETCH_NORMAL,
136 DWRITE_FONT_STYLE_NORMAL,
137 &matchingFonts))) {
138 for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) {
139 IDWriteFont *font;
140 if (SUCCEEDED(matchingFonts->GetFont(j, &font))) {
141 DirectWriteScope<IDWriteFont1> font1;
142 if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1),
143 reinterpret_cast<void **>(&font1)))) {
144 qCWarning(lcQpaFonts) << "COM object does not support IDWriteFont1";
145 continue;
146 }
147
148 QString defaultLocaleFamilyName;
149 QString englishLocaleFamilyName;
150
151 DirectWriteScope<IDWriteFontFamily> fontFamily2;
152 if (SUCCEEDED(font1->GetFontFamily(&fontFamily2))) {
153 DirectWriteScope<IDWriteLocalizedStrings> names;
154 if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) {
155 defaultLocaleFamilyName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
156 englishLocaleFamilyName = localeString(*names, englishLocale);
157 }
158 }
159
160 if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty())
161 englishLocaleFamilyName = familyName;
162
163 {
164 DirectWriteScope<IDWriteLocalizedStrings> names;
165 if (SUCCEEDED(font1->GetFaceNames(&names))) {
166 QString defaultLocaleStyleName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
167 QString englishLocaleStyleName = localeString(*names, englishLocale);
168
169 QFont::Stretch stretch = fromDirectWriteStretch(font1->GetStretch());
170 QFont::Style style = fromDirectWriteStyle(font1->GetStyle());
171 QFont::Weight weight = fromDirectWriteWeight(font1->GetWeight());
172 bool fixed = font1->IsMonospacedFont();
173
174 qCDebug(lcQpaFonts) << "Family" << familyName << "has english variant" << englishLocaleStyleName << ", in default locale:" << defaultLocaleStyleName << stretch << style << weight << fixed;
175
176 DirectWriteScope<IDWriteFontFace> face;
177 if (SUCCEEDED(font->CreateFontFace(&face))) {
178 QSupportedWritingSystems writingSystems = supportedWritingSystems(*face);
179
180 if (!englishLocaleStyleName.isEmpty() || defaultLocaleStyleName.isEmpty()) {
181 qCDebug(lcQpaFonts) << "Font" << englishLocaleFamilyName << englishLocaleStyleName << "supports writing systems:" << writingSystems;
182
183 QPlatformFontDatabase::registerFont(englishLocaleFamilyName,
184 englishLocaleStyleName,
185 QString(),
186 weight,
187 style,
188 stretch,
189 antialias,
190 scalable,
191 size,
192 fixed,
193 writingSystems,
194 new FontHandle(*face, englishLocaleFamilyName));
195 }
196
197 if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) {
198 QPlatformFontDatabase::registerFont(defaultLocaleFamilyName,
199 defaultLocaleStyleName,
200 QString(),
201 weight,
202 style,
203 stretch,
204 antialias,
205 scalable,
206 size,
207 fixed,
208 writingSystems,
209 new FontHandle(*face, defaultLocaleFamilyName));
210 }
211 }
212 }
213 }
214 }
215 }
216 }
217}
218
219QSupportedWritingSystems QWindowsDirectWriteFontDatabase::supportedWritingSystems(IDWriteFontFace *face) const
220{
221 QSupportedWritingSystems writingSystems;
222 writingSystems.setSupported(QFontDatabase::Any);
223
224 DirectWriteScope<IDWriteFontFace1> face1;
225 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace1),
226 reinterpret_cast<void **>(&face1)))) {
227 const void *tableData = nullptr;
228 UINT32 tableSize;
229 void *tableContext = nullptr;
230 BOOL exists;
231 HRESULT hr = face->TryGetFontTable(qFromBigEndian(QFont::Tag("OS/2").value()),
232 &tableData,
233 &tableSize,
234 &tableContext,
235 &exists);
236 if (SUCCEEDED(hr) && exists) {
237 writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(tableData), tableSize);
238 } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems)
239 quint32 rangeCount;
240 hr = face1->GetUnicodeRanges(0, nullptr, &rangeCount);
241
242 if (rangeCount > 0) {
243 QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount);
244
245 hr = face1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount);
246 if (SUCCEEDED(hr)) {
247 for (uint i = 0; i < rangeCount; ++i) {
248 QChar::Script script = QChar::script(ranges.at(i).first);
249
251
252 if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount)
253 writingSystems.setSupported(writingSystem);
254 }
255 } else {
256 const QString errorString = qt_error_string(int(hr));
257 qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font:" << errorString;
258 }
259 }
260 }
261 }
262
263 return writingSystems;
264}
265
267{
268 // If the font has not been populated, it is possible this is a legacy font family supported
269 // by GDI. We make an attempt at loading it via GDI and then add this face directly to the
270 // database.
271 if (!missingFamily.isEmpty()
272 && missingFamily.size() < LF_FACESIZE
273 && !m_populatedFonts.contains(missingFamily)
274 && !m_populatedBitmapFonts.contains(missingFamily)) {
275 qCDebug(lcQpaFonts) << "Loading unpopulated" << missingFamily << ". Trying GDI.";
276
277 LOGFONT lf;
278 memset(&lf, 0, sizeof(LOGFONT));
279 memcpy(lf.lfFaceName, missingFamily.utf16(), missingFamily.size() * sizeof(wchar_t));
280
281 HFONT hfont = CreateFontIndirect(&lf);
282 if (hfont) {
283 HDC dummy = GetDC(0);
284 HGDIOBJ oldFont = SelectObject(dummy, hfont);
285
286 DirectWriteScope<IDWriteFontFace> directWriteFontFace;
287 if (SUCCEEDED(data()->directWriteGdiInterop->CreateFontFaceFromHdc(dummy, &directWriteFontFace))) {
288 DirectWriteScope<IDWriteFontCollection> fontCollection;
289 if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) {
290 DirectWriteScope<IDWriteFont> font;
291 if (SUCCEEDED(fontCollection->GetFontFromFontFace(*directWriteFontFace, &font))) {
292
293 DirectWriteScope<IDWriteFont1> font1;
294 if (SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1),
295 reinterpret_cast<void **>(&font1)))) {
296 DirectWriteScope<IDWriteLocalizedStrings> names;
297 if (SUCCEEDED(font1->GetFaceNames(&names))) {
298 wchar_t englishLocale[] = L"en-us";
299 QString englishLocaleStyleName = localeString(*names, englishLocale);
300
301 QFont::Stretch stretch = fromDirectWriteStretch(font1->GetStretch());
302 QFont::Style style = fromDirectWriteStyle(font1->GetStyle());
303 QFont::Weight weight = fromDirectWriteWeight(font1->GetWeight());
304 bool fixed = font1->IsMonospacedFont();
305
306 QSupportedWritingSystems writingSystems = supportedWritingSystems(*directWriteFontFace);
307
308 qCDebug(lcQpaFonts) << "Registering legacy font family" << missingFamily;
310 englishLocaleStyleName,
311 QString(),
312 weight,
313 style,
314 stretch,
315 false,
316 true,
317 0xffff,
318 fixed,
319 writingSystems,
320 new FontHandle(*directWriteFontFace, missingFamily));
321
322 SelectObject(dummy, oldFont);
323 DeleteObject(hfont);
324
325 return true;
326 }
327 }
328 }
329 }
330 }
331
332 SelectObject(dummy, oldFont);
333 DeleteObject(hfont);
334 }
335 }
336
337 // Skip over implementation in QWindowsFontDatabase
339}
340
342 qreal pixelSize,
343 QFont::HintingPreference hintingPreference)
344{
345 // Skip over implementation in QWindowsFontDatabase
346 return QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
347}
348
350{
351 const FontHandle *fontHandle = static_cast<const FontHandle *>(handle);
352 IDWriteFontFace *face = fontHandle->fontFace;
353 if (face == nullptr) {
354 qCDebug(lcQpaFonts) << "Falling back to GDI";
356 }
357
358 DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
359 if (fontDef.weight >= QFont::DemiBold || fontDef.style != QFont::StyleNormal) {
360 DirectWriteScope<IDWriteFontFace3> face3;
361 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
362 reinterpret_cast<void **>(&face3)))) {
363 if (fontDef.weight >= QFont::DemiBold && face3->GetWeight() < DWRITE_FONT_WEIGHT_DEMI_BOLD)
364 simulations |= DWRITE_FONT_SIMULATIONS_BOLD;
365
366 if (fontDef.style != QFont::StyleNormal && face3->GetStyle() == DWRITE_FONT_STYLE_NORMAL)
367 simulations |= DWRITE_FONT_SIMULATIONS_OBLIQUE;
368 }
369 }
370
371 DirectWriteScope<IDWriteFontFace5> newFace;
372 if (!fontDef.variableAxisValues.isEmpty() || simulations != DWRITE_FONT_SIMULATIONS_NONE) {
373 DirectWriteScope<IDWriteFontFace5> face5;
374 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace5),
375 reinterpret_cast<void **>(&face5)))) {
376 DirectWriteScope<IDWriteFontResource> font;
377 if (SUCCEEDED(face5->GetFontResource(&font))) {
378 UINT32 fontAxisCount = font->GetFontAxisCount();
379 QVarLengthArray<DWRITE_FONT_AXIS_VALUE, 8> fontAxisValues(fontAxisCount);
380
381 if (!fontDef.variableAxisValues.isEmpty()) {
382 if (SUCCEEDED(face5->GetFontAxisValues(fontAxisValues.data(), fontAxisCount))) {
383 for (UINT32 i = 0; i < fontAxisCount; ++i) {
384 if (auto maybeTag = QFont::Tag::fromValue(qToBigEndian<UINT32>(fontAxisValues[i].axisTag))) {
385 if (fontDef.variableAxisValues.contains(*maybeTag))
386 fontAxisValues[i].value = fontDef.variableAxisValues.value(*maybeTag);
387 }
388 }
389 }
390 }
391
392 if (SUCCEEDED(font->CreateFontFace(simulations,
393 !fontDef.variableAxisValues.isEmpty() ? fontAxisValues.data() : nullptr,
394 !fontDef.variableAxisValues.isEmpty() ? fontAxisCount : 0,
395 &newFace))) {
396 face = *newFace;
397 } else {
398 qCWarning(lcQpaFonts) << "DirectWrite: Can't create font face for variable axis values";
399 }
400 }
401 }
402 }
403
405 fontEngine->initFontInfo(fontDef, defaultVerticalDPI());
406
407 return fontEngine;
408}
409
411{
413 result.append(familyForStyleHint(styleHint));
414 result.append(extraTryFontsForFamily(family));
415 result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script));
416
417 qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
418 << script << result;
419 return result;
420}
421
423{
424 qCDebug(lcQpaFonts) << "Adding application font" << fileName;
425
426 QByteArray loadedData = fontData;
427 if (loadedData.isEmpty()) {
430 qCWarning(lcQpaFonts) << "Cannot open" << fileName << "for reading.";
431 return QStringList();
432 }
433 loadedData = file.readAll();
434 }
435
436 QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData);
437 if (faces.isEmpty()) {
438 qCWarning(lcQpaFonts) << "Failed to create DirectWrite face from font data. Font may be unsupported.";
439 return QStringList();
440 }
441
442 QSet<QString> ret;
443 for (int i = 0; i < faces.size(); ++i) {
444 IDWriteFontFace *face = faces.at(i);
445 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
446 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
447 wchar_t englishLocale[] = L"en-us";
448
449 static const int SMOOTH_SCALABLE = 0xffff;
450 const bool scalable = true;
451 const bool antialias = false;
452 const int size = SMOOTH_SCALABLE;
453
454 QSupportedWritingSystems writingSystems = supportedWritingSystems(face);
455 DirectWriteScope<IDWriteFontFace3> face3;
456 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
457 reinterpret_cast<void **>(&face3)))) {
458 QString defaultLocaleFamilyName;
459 QString englishLocaleFamilyName;
460
461 IDWriteLocalizedStrings *names = nullptr;
462 if (SUCCEEDED(face3->GetFamilyNames(&names))) {
463 defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
464 englishLocaleFamilyName = localeString(names, englishLocale);
465
466 names->Release();
467 }
468
469 QString defaultLocaleStyleName;
470 QString englishLocaleStyleName;
471 if (SUCCEEDED(face3->GetFaceNames(&names))) {
472 defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
473 englishLocaleStyleName = localeString(names, englishLocale);
474
475 names->Release();
476 }
477
478 BOOL ok;
479 QString defaultLocaleGdiCompatibleFamilyName;
480 QString englishLocaleGdiCompatibleFamilyName;
481 if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &ok)) && ok) {
482 defaultLocaleGdiCompatibleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
483 englishLocaleGdiCompatibleFamilyName = localeString(names, englishLocale);
484
485 names->Release();
486 }
487
488 QString defaultLocaleGdiCompatibleStyleName;
489 QString englishLocaleGdiCompatibleStyleName;
490 if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, &names, &ok)) && ok) {
491 defaultLocaleGdiCompatibleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
492 englishLocaleGdiCompatibleStyleName = localeString(names, englishLocale);
493
494 names->Release();
495 }
496
497 QString defaultLocaleTypographicFamilyName;
498 QString englishLocaleTypographicFamilyName;
499 if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_FAMILY_NAMES, &names, &ok)) && ok) {
500 defaultLocaleTypographicFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
501 englishLocaleTypographicFamilyName = localeString(names, englishLocale);
502
503 names->Release();
504 }
505
506 QString defaultLocaleTypographicStyleName;
507 QString englishLocaleTypographicStyleName;
508 if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_SUBFAMILY_NAMES, &names, &ok)) && ok) {
509 defaultLocaleTypographicStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
510 englishLocaleTypographicStyleName = localeString(names, englishLocale);
511
512 names->Release();
513 }
514
515 QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch());
516 QFont::Style style = fromDirectWriteStyle(face3->GetStyle());
517 QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight());
518 bool fixed = face3->IsMonospacedFont();
519
520 qCDebug(lcQpaFonts) << "\tFont names:" << englishLocaleFamilyName << ", " << defaultLocaleFamilyName
521 << ", style names:" << englishLocaleStyleName << ", " << defaultLocaleStyleName
522 << ", stretch:" << stretch
523 << ", style:" << style
524 << ", weight:" << weight
525 << ", fixed:" << fixed;
526
527 if (!englishLocaleFamilyName.isEmpty()) {
528 if (applicationFont != nullptr) {
530 properties.style = style;
531 properties.weight = weight;
532 properties.familyName = englishLocaleFamilyName;
533 properties.styleName = englishLocaleStyleName;
534 applicationFont->properties.append(properties);
535 }
536
537 ret.insert(englishLocaleFamilyName);
538 QPlatformFontDatabase::registerFont(englishLocaleFamilyName,
539 englishLocaleStyleName,
540 QString(),
541 weight,
542 style,
543 stretch,
544 antialias,
545 scalable,
546 size,
547 fixed,
548 writingSystems,
549 new FontHandle(face, englishLocaleFamilyName));
550 }
551
552 if (!defaultLocaleFamilyName.isEmpty() && !ret.contains(defaultLocaleFamilyName)) {
553 if (applicationFont != nullptr) {
555 properties.style = style;
556 properties.weight = weight;
557 properties.familyName = englishLocaleFamilyName;
558 properties.styleName = englishLocaleStyleName;
559 applicationFont->properties.append(properties);
560 }
561
562 ret.insert(defaultLocaleFamilyName);
563 QPlatformFontDatabase::registerFont(defaultLocaleFamilyName,
564 defaultLocaleStyleName,
565 QString(),
566 weight,
567 style,
568 stretch,
569 antialias,
570 scalable,
571 size,
572 fixed,
573 writingSystems,
574 new FontHandle(face, defaultLocaleFamilyName));
575 }
576
577 if (!englishLocaleGdiCompatibleFamilyName.isEmpty() &&
578 !ret.contains(englishLocaleGdiCompatibleFamilyName)) {
579 if (applicationFont != nullptr) {
581 properties.style = style;
582 properties.weight = weight;
583 properties.familyName = englishLocaleGdiCompatibleFamilyName;
584 applicationFont->properties.append(properties);
585 }
586
587 ret.insert(englishLocaleGdiCompatibleFamilyName);
588 QPlatformFontDatabase::registerFont(englishLocaleGdiCompatibleFamilyName,
589 englishLocaleGdiCompatibleStyleName,
590 QString(),
591 weight,
592 style,
593 stretch,
594 antialias,
595 scalable,
596 size,
597 fixed,
598 writingSystems,
599 new FontHandle(face, englishLocaleGdiCompatibleFamilyName));
600 }
601
602 if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
603 && !ret.contains(defaultLocaleGdiCompatibleFamilyName)) {
604 if (applicationFont != nullptr) {
606 properties.style = style;
607 properties.weight = weight;
608 properties.familyName = defaultLocaleGdiCompatibleFamilyName;
609 applicationFont->properties.append(properties);
610 }
611
612 ret.insert(defaultLocaleGdiCompatibleFamilyName);
613 QPlatformFontDatabase::registerFont(defaultLocaleGdiCompatibleFamilyName,
614 defaultLocaleGdiCompatibleStyleName,
615 QString(),
616 weight,
617 style,
618 stretch,
619 antialias,
620 scalable,
621 size,
622 fixed,
623 writingSystems,
624 new FontHandle(face, defaultLocaleGdiCompatibleFamilyName));
625 }
626
627 if (!englishLocaleTypographicFamilyName.isEmpty()
628 && !ret.contains(englishLocaleTypographicFamilyName)) {
629 if (applicationFont != nullptr) {
631 properties.style = style;
632 properties.weight = weight;
633 properties.familyName = englishLocaleTypographicFamilyName;
634 applicationFont->properties.append(properties);
635 }
636
637 ret.insert(englishLocaleTypographicFamilyName);
638 QPlatformFontDatabase::registerFont(englishLocaleTypographicFamilyName,
639 englishLocaleTypographicStyleName,
640 QString(),
641 weight,
642 style,
643 stretch,
644 antialias,
645 scalable,
646 size,
647 fixed,
648 writingSystems,
649 new FontHandle(face, englishLocaleTypographicFamilyName));
650 }
651
652 if (!defaultLocaleTypographicFamilyName.isEmpty()
653 && !ret.contains(defaultLocaleTypographicFamilyName)) {
654 if (applicationFont != nullptr) {
656 properties.style = style;
657 properties.weight = weight;
658 properties.familyName = defaultLocaleTypographicFamilyName;
659 applicationFont->properties.append(properties);
660 }
661
662 ret.insert(defaultLocaleTypographicFamilyName);
663 QPlatformFontDatabase::registerFont(defaultLocaleTypographicFamilyName,
664 defaultLocaleTypographicStyleName,
665 QString(),
666 weight,
667 style,
668 stretch,
669 antialias,
670 scalable,
671 size,
672 fixed,
673 writingSystems,
674 new FontHandle(face, defaultLocaleTypographicFamilyName));
675 }
676
677 } else {
678 qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face.";
679 }
680
681 face->Release();
682 }
683
684 return ret.values();
685}
686
688{
689 Q_UNUSED(family);
690 return false;
691}
692
693static int QT_WIN_CALLBACK populateBitmapFonts(const LOGFONT *logFont,
694 const TEXTMETRIC *textmetric,
695 DWORD type,
696 LPARAM lparam)
697{
698 Q_UNUSED(textmetric);
699
700 // the "@family" fonts are just the same as "family". Ignore them.
701 const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
702 const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
703 if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
704 const QString faceName = QString::fromWCharArray(faceNameW);
705 if (type & RASTER_FONTTYPE || type == 0) {
707 if (!db->hasPopulatedFont(faceName)) {
708 db->registerFontFamily(faceName);
709 db->registerBitmapFont(faceName);
710 }
711 }
712 }
713 return 1; // continue
714}
715
717{
718 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
719 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
720 wchar_t englishLocale[] = L"en-us";
721
722 const QString defaultFontName = defaultFont().families().constFirst();
723 const QString systemDefaultFontName = systemDefaultFont().families().constFirst();
724
725 DirectWriteScope<IDWriteFontCollection2> fontCollection;
726 DirectWriteScope<IDWriteFactory6> factory6;
727 if (FAILED(data()->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory6),
728 reinterpret_cast<void **>(&factory6)))) {
729 qCWarning(lcQpaFonts) << "Can't initialize IDWriteFactory6. Use GDI font engine instead.";
730 return;
731 }
732
733 if (SUCCEEDED(factory6->GetSystemFontCollection(false,
734 DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
735 &fontCollection))) {
736 for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) {
737 DirectWriteScope<IDWriteFontFamily2> fontFamily;
738 if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) {
739 QString defaultLocaleName;
740 QString englishLocaleName;
741
742 DirectWriteScope<IDWriteLocalizedStrings> names;
743 if (SUCCEEDED(fontFamily->GetFamilyNames(&names))) {
744 if (hasDefaultLocale)
745 defaultLocaleName = localeString(*names, defaultLocale);
746
747 englishLocaleName = localeString(*names, englishLocale);
748 }
749
750 qCDebug(lcQpaFonts) << "Registering font, english name = " << englishLocaleName << ", name in current locale = " << defaultLocaleName;
751 if (!defaultLocaleName.isEmpty()) {
752 registerFontFamily(defaultLocaleName);
753 m_populatedFonts.insert(defaultLocaleName, *fontFamily);
754 fontFamily->AddRef();
755
756 if (defaultLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
757 qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << defaultLocaleName;
758
759 m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
760 fontFamily->AddRef();
761 }
762 }
763
764 if (!englishLocaleName.isEmpty() && englishLocaleName != defaultLocaleName) {
765 registerFontFamily(englishLocaleName);
766 m_populatedFonts.insert(englishLocaleName, *fontFamily);
767 fontFamily->AddRef();
768
769 if (englishLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
770 qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << englishLocaleName;
771
772 m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
773 fontFamily->AddRef();
774 }
775 }
776 }
777 }
778 }
779
780 // Since bitmap fonts are not supported by DirectWrite, we need to populate these as well
781 {
782 HDC dummy = GetDC(0);
783 LOGFONT lf;
784 lf.lfCharSet = DEFAULT_CHARSET;
785 lf.lfFaceName[0] = 0;
786 lf.lfPitchAndFamily = 0;
787 EnumFontFamiliesEx(dummy, &lf, populateBitmapFonts, reinterpret_cast<intptr_t>(this), 0);
788 ReleaseDC(0, dummy);
789 }
790}
791
796
798{
799 QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
800 DirectWriteScope<IDWriteFactory5> factory5;
801 if (SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
802 reinterpret_cast<void **>(&factory5)))) {
803 return true;
804 }
805
806 return false;
807}
808
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
WritingSystem
\value Any \value Latin \value Greek \value Cyrillic \value Armenian \value Hebrew \value Arabic \val...
\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
QStringList families() const
Definition qfont.cpp:2699
HintingPreference
Definition qfont.h:55
Stretch
Predefined stretch values that follow the CSS naming convention.
Definition qfont.h:83
@ AnyStretch
Definition qfont.h:84
@ ExtraCondensed
Definition qfont.h:86
@ Expanded
Definition qfont.h:91
@ Unstretched
Definition qfont.h:89
@ SemiCondensed
Definition qfont.h:88
@ SemiExpanded
Definition qfont.h:90
@ UltraCondensed
Definition qfont.h:85
@ ExtraExpanded
Definition qfont.h:92
@ Condensed
Definition qfont.h:87
@ UltraExpanded
Definition qfont.h:93
Weight
Qt uses a weighting scale from 1 to 1000 compatible with OpenType.
Definition qfont.h:63
@ DemiBold
Definition qfont.h:69
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
@ StyleOblique
Definition qfont.h:79
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1291
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
Definition qhash.h:1007
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
bool contains(const Key &key) const
Definition qmap.h:341
bool isEmpty() const
Definition qmap.h:269
virtual bool populateFamilyAliases(const QString &missingFamily)
static QSupportedWritingSystems writingSystemsFromOS2Table(const char *os2Table, size_t length)
Helper function that determines the writing system support based on the contents of the OS/2 table in...
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...
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,...
bool contains(const T &value) const
Definition qset.h:71
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1309
The QSupportedWritingSystems class is used when registering fonts with the internal Qt fontdatabase.
void setSupported(QFontDatabase::WritingSystem, bool supported=true)
Sets or clears support for the specified writingSystem based on the value given by support.
bool supportsVariableApplicationFonts() const override
Returns true if this font database supports loading named instances from variable application fonts.
void populateFontDatabase() override
This function is called once at startup by Qt's internal font database.
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *font=nullptr) override
Adds an application font described by the font contained supplied fontData or using the font containe...
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,...
bool populateFamilyAliases(const QString &missingFamily) override
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...
QFont defaultFont() const override
Returns the default system font.
void populateFamily(const QString &familyName) override
This function is called whenever a lazily populated family, populated through registerFontFamily(),...
bool isPrivateFontFamily(const QString &family) const override
Returns true if the font family is private.
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 QStringList extraTryFontsForFamily(const QString &family)
static QSharedPointer< QWindowsFontEngineData > data()
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,...
void populateFamily(const QString &familyName) override
This function is called whenever a lazily populated family, populated through registerFontFamily(),...
Windows font engine using Direct Write.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
Q_MULTIMEDIA_EXPORT QString errorString(HRESULT hr)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
static const QCssKnownValue properties[NumProperties - 1]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
constexpr T qFromBigEndian(T source)
Definition qendian.h:174
INT_PTR intptr_t
#define SMOOTH_SCALABLE
Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script)
Q_DECL_COLD_FUNCTION Q_CORE_EXPORT QString qt_error_string(int errorCode=-1)
#define qDebug
[1]
Definition qlogging.h:164
#define qCWarning(category,...)
#define qCDebug(category,...)
return ret
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum face
GLfloat GLfloat f
GLuint GLuint GLfloat weight
GLenum GLuint buffer
GLenum type
GLenum GLsizeiptr const void * fontData
GLuint res
GLuint GLuint * names
GLuint64EXT * result
[6]
#define QStringLiteral(str)
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
long HRESULT
static int QT_WIN_CALLBACK populateBitmapFonts(const LOGFONT *logFont, const TEXTMETRIC *textmetric, DWORD type, LPARAM lparam)
static QFont::Stretch fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch)
static QFont::Weight fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight)
QT_BEGIN_NAMESPACE Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script)
static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style)
QFile file
[0]
QMimeDatabase db
[0]
uint style
Definition qfont_p.h:66
qreal pixelSize
Definition qfont_p.h:61
QMap< QFont::Tag, float > variableAxisValues
Definition qfont_p.h:58
uint weight
Definition qfont_p.h:70
The QFont::Tag type provides access to advanced font features.
Definition qfont.h:215