111void QWindowsDirectWriteFontDatabase::populateFamily(
const QString &familyName)
113 auto it = m_populatedFonts.find(familyName);
114 if (it == m_populatedFonts.end() && m_populatedBitmapFonts.contains(familyName)) {
115 qCDebug(lcQpaFonts) <<
"Populating bitmap font" << familyName;
116 QWindowsFontDatabase::populateFamily(familyName);
120 IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() :
nullptr;
121 if (fontFamily ==
nullptr) {
122 qCWarning(lcQpaFonts) <<
"Cannot find" << familyName <<
"in list of fonts";
126 qCDebug(lcQpaFonts) <<
"Populate family:" << familyName;
128 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
129 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
130 wchar_t englishLocale[] = L"en-us";
132 static const int SMOOTH_SCALABLE = 0xffff;
133 const QString foundryName;
134 const bool scalable =
true;
135 const bool antialias =
false;
136 const int size = SMOOTH_SCALABLE;
138 DirectWriteScope<IDWriteFontList> matchingFonts;
139 if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR,
140 DWRITE_FONT_STRETCH_NORMAL,
141 DWRITE_FONT_STYLE_NORMAL,
143 for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) {
144 DirectWriteScope<IDWriteFont> font;
145 if (SUCCEEDED(matchingFonts->GetFont(j, &font))) {
146 DirectWriteScope<IDWriteFont2> font2;
147 if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont2),
148 reinterpret_cast<
void **>(&font2)))) {
149 qCWarning(lcQpaFonts) <<
"COM object does not support IDWriteFont1";
153 QString defaultLocaleFamilyName;
154 QString englishLocaleFamilyName;
155 QString defaultLocaleGdiCompatibleFamilyName;
156 QString englishLocaleGdiCompatibleFamilyName;
158 DirectWriteScope<IDWriteFontFamily> fontFamily2;
159 if (SUCCEEDED(font2->GetFontFamily(&fontFamily2))) {
160 DirectWriteScope<IDWriteLocalizedStrings> names;
161 if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) {
162 defaultLocaleFamilyName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
163 englishLocaleFamilyName = localeString(*names, englishLocale);
167 if (SUCCEEDED(font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &ok)) && ok) {
168 defaultLocaleGdiCompatibleFamilyName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
169 englishLocaleGdiCompatibleFamilyName = localeString(*names, englishLocale);
173 if (defaultLocaleFamilyName.isEmpty()
174 && englishLocaleFamilyName.isEmpty()
175 && englishLocaleGdiCompatibleFamilyName.isEmpty()
176 && defaultLocaleGdiCompatibleFamilyName.isEmpty()) {
177 englishLocaleFamilyName = familyName;
180 QFont::Stretch stretch = fromDirectWriteStretch(font2->GetStretch());
181 QFont::Style style = fromDirectWriteStyle(font2->GetStyle());
182 QFont::Weight weight = fromDirectWriteWeight(font2->GetWeight());
183 bool fixed = font2->IsMonospacedFont();
184 bool color = font2->IsColorFont();
186 DirectWriteScope<IDWriteFontFace> face;
187 if (SUCCEEDED(font->CreateFontFace(&face))) {
188 QSupportedWritingSystems writingSystems = supportedWritingSystems(*face);
190 auto registerFontName = [&](
const QString &rFamilyName,
191 const QString &rStyleName) {
192 qCDebug(lcQpaFonts) <<
"Family" << familyName <<
"has variant"
193 << rFamilyName <<
", "
194 << rStyleName <<
", "
200 QPlatformFontDatabase::registerFont(rFamilyName,
212 new FontHandle(*face, rFamilyName));
216 DirectWriteScope<IDWriteLocalizedStrings> names;
217 if (SUCCEEDED(font2->GetFaceNames(&names))) {
218 QString defaultLocaleStyleName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
219 QString englishLocaleStyleName = localeString(*names, englishLocale);
220 qCDebug(lcQpaFonts) <<
">>> Storing English locale names";
221 registerFontName(englishLocaleFamilyName, englishLocaleStyleName);
225 if (!defaultLocaleFamilyName.isEmpty()
226 && defaultLocaleFamilyName != englishLocaleFamilyName) {
227 qCDebug(lcQpaFonts) <<
">>> Storing default locale names";
228 registerFontName(defaultLocaleFamilyName, defaultLocaleStyleName);
233 if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
234 || !englishLocaleGdiCompatibleFamilyName.isEmpty()) {
235 QString defaultLocaleGdiCompatibleStyleName;
236 QString englishLocaleGdiCompatibleStyleName;
238 DirectWriteScope<IDWriteLocalizedStrings> names;
240 if (SUCCEEDED(font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, &names, &ok)) && ok) {
241 defaultLocaleGdiCompatibleStyleName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
242 englishLocaleGdiCompatibleStyleName = localeString(*names, englishLocale);
244 if (!englishLocaleGdiCompatibleFamilyName.isEmpty()
245 && englishLocaleGdiCompatibleFamilyName != englishLocaleFamilyName) {
246 qCDebug(lcQpaFonts) <<
">>> Storing English GDI compatible names";
247 registerFontName(englishLocaleGdiCompatibleFamilyName,
248 englishLocaleGdiCompatibleStyleName);
251 if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
252 && defaultLocaleGdiCompatibleFamilyName != englishLocaleGdiCompatibleFamilyName
253 && defaultLocaleGdiCompatibleFamilyName != defaultLocaleFamilyName) {
254 qCDebug(lcQpaFonts) <<
">>> Storing Default locale GDI compatible names";
255 registerFontName(defaultLocaleGdiCompatibleFamilyName,
256 defaultLocaleGdiCompatibleStyleName);
330QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(
const QFontDef &fontDef,
void *handle)
332 const FontHandle *fontHandle =
static_cast<
const FontHandle *>(handle);
333 IDWriteFontFace *face = fontHandle->fontFace;
334 if (face ==
nullptr) {
335 qCDebug(lcQpaFonts) <<
"Falling back to GDI";
336 return QWindowsFontDatabase::fontEngine(fontDef, handle);
339 DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
340 if (fontDef.weight >= QFont::DemiBold || fontDef.style != QFont::StyleNormal) {
341 DirectWriteScope<IDWriteFontFace3> face3;
342 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
343 reinterpret_cast<
void **>(&face3)))) {
344 if (fontDef.weight >= QFont::DemiBold && face3->GetWeight() < DWRITE_FONT_WEIGHT_DEMI_BOLD)
345 simulations |= DWRITE_FONT_SIMULATIONS_BOLD;
347 if (fontDef.style != QFont::StyleNormal && face3->GetStyle() == DWRITE_FONT_STYLE_NORMAL)
348 simulations |= DWRITE_FONT_SIMULATIONS_OBLIQUE;
352 DirectWriteScope<IDWriteFontFace5> newFace;
353 if (!fontDef.variableAxisValues.isEmpty() || simulations != DWRITE_FONT_SIMULATIONS_NONE) {
354 DirectWriteScope<IDWriteFontFace5> face5;
355 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace5),
356 reinterpret_cast<
void **>(&face5)))) {
357 DirectWriteScope<IDWriteFontResource> font;
358 if (SUCCEEDED(face5->GetFontResource(&font))) {
359 UINT32 fontAxisCount = font->GetFontAxisCount();
360 QVarLengthArray<DWRITE_FONT_AXIS_VALUE, 8> fontAxisValues(fontAxisCount);
362 if (!fontDef.variableAxisValues.isEmpty()) {
363 if (SUCCEEDED(face5->GetFontAxisValues(fontAxisValues.data(), fontAxisCount))) {
364 for (UINT32 i = 0; i < fontAxisCount; ++i) {
365 if (
auto maybeTag = QFont::Tag::fromValue(qToBigEndian<UINT32>(fontAxisValues[i].axisTag))) {
366 if (fontDef.variableAxisValues.contains(*maybeTag))
367 fontAxisValues[i].value = fontDef.variableAxisValues.value(*maybeTag);
373 if (SUCCEEDED(font->CreateFontFace(simulations,
374 !fontDef.variableAxisValues.isEmpty() ? fontAxisValues.data() :
nullptr,
375 !fontDef.variableAxisValues.isEmpty() ? fontAxisCount : 0,
379 qCWarning(lcQpaFonts) <<
"DirectWrite: Can't create font face for variable axis values";
385 QWindowsFontEngineDirectWrite *fontEngine =
new QWindowsFontEngineDirectWrite(face, fontDef.pixelSize, data());
386 fontEngine->initFontInfo(fontDef, defaultVerticalDPI());
498QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(
const QByteArray &fontData,
const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
500 qCDebug(lcQpaFonts) <<
"Adding application font" << fileName;
502 QByteArray loadedData = fontData;
503 if (loadedData.isEmpty()) {
504 QFile file(fileName);
505 if (!file.open(QIODevice::ReadOnly)) {
506 qCWarning(lcQpaFonts) <<
"Cannot open" << fileName <<
"for reading.";
507 return QStringList();
509 loadedData = file.readAll();
512 QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData, fileName);
513 if (faces.isEmpty()) {
514 qCWarning(lcQpaFonts) <<
"Failed to create DirectWrite face from font data. Font may be unsupported.";
515 return QStringList();
518 QSet<FontInfo> registeredFonts;
520 for (
int i = 0; i < faces.size(); ++i) {
521 IDWriteFontFace *face = faces.at(i);
522 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
523 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
524 wchar_t englishLocale[] = L"en-us";
526 constexpr int SMOOTH_SCALABLE = 0xffff;
527 constexpr bool scalable =
true;
528 constexpr bool antialias =
false;
529 constexpr int size = SMOOTH_SCALABLE;
531 QSupportedWritingSystems writingSystems = supportedWritingSystems(face);
532 DirectWriteScope<IDWriteFontFace3> face3;
533 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
534 reinterpret_cast<
void **>(&face3)))) {
536 QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch());
537 QFont::Style style = fromDirectWriteStyle(face3->GetStyle());
538 QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight());
539 bool fixed = face3->IsMonospacedFont();
540 bool color = face3->IsColorFont();
542 auto registerFamilyAndStyle = [®isteredFonts,
551 color](
const QString &familyName,
552 const QString &styleName)
554 FontInfo fontInfo = { stretch, style, weight, familyName, styleName };
555 if (registeredFonts.contains(fontInfo))
557 registeredFonts.insert(fontInfo);
558 ret.insert(familyName);
560 qCDebug(lcQpaFonts) <<
"\tRegistering alternative:" << familyName
562 <<
", stretch =" << stretch
563 <<
", style =" << style
564 <<
", weight =" << weight
565 <<
", fixed =" << fixed
566 <<
", color =" << color;
567 if (applicationFont !=
nullptr) {
568 QFontDatabasePrivate::ApplicationFont::Properties properties;
569 properties.style = style;
570 properties.weight = weight;
571 properties.familyName = familyName;
572 properties.styleName = styleName;
573 properties.stretch = stretch;
574 applicationFont->properties.append(properties);
577 QPlatformFontDatabase::registerFont(familyName,
589 new FontHandle(face, familyName));
592 QString defaultLocaleFamilyName;
593 QString englishLocaleFamilyName;
595 IDWriteLocalizedStrings *names =
nullptr;
596 if (SUCCEEDED(face3->GetFamilyNames(&names))) {
597 defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
598 englishLocaleFamilyName = localeString(names, englishLocale);
603 QString defaultLocaleStyleName;
604 QString englishLocaleStyleName;
605 if (SUCCEEDED(face3->GetFaceNames(&names))) {
606 defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
607 englishLocaleStyleName = localeString(names, englishLocale);
612 qCDebug(lcQpaFonts) <<
"\tFont names:" << englishLocaleFamilyName <<
", " << defaultLocaleFamilyName
613 <<
", style names:" << englishLocaleStyleName <<
", " << defaultLocaleStyleName
614 <<
", stretch:" << stretch
615 <<
", style:" << style
616 <<
", weight:" << weight
617 <<
", fixed:" << fixed;
619 if (!englishLocaleFamilyName.isEmpty())
620 registerFamilyAndStyle(englishLocaleFamilyName, englishLocaleStyleName);
622 if (!defaultLocaleFamilyName.isEmpty())
623 registerFamilyAndStyle(defaultLocaleFamilyName, defaultLocaleStyleName);
625 collectAdditionalNames(*face3,
626 hasDefaultLocale ? defaultLocale :
nullptr,
628 registerFamilyAndStyle);
631 qCWarning(lcQpaFonts) <<
"Unable to query IDWriteFontFace3 interface from font face.";
669void QWindowsDirectWriteFontDatabase::populateFontDatabase()
671 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
672 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
673 wchar_t englishLocale[] = L"en-us";
675 const QString defaultFontName = defaultFont().family();
676 const QString systemDefaultFontName = systemDefaultFont().family();
678 DirectWriteScope<IDWriteFontCollection2> fontCollection;
679 DirectWriteScope<IDWriteFactory6> factory6;
680 if (FAILED(data()->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory6),
681 reinterpret_cast<
void **>(&factory6)))) {
682 qCWarning(lcQpaFonts) <<
"Can't initialize IDWriteFactory6. Use GDI font engine instead.";
686 if (SUCCEEDED(factory6->GetSystemFontCollection(
false,
687 DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
689 QSet<QString> registeredFamilies;
690 for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) {
691 DirectWriteScope<IDWriteFontFamily2> fontFamily;
692 if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) {
693 auto registerFamily = [&](
const QString &familyName,
const QString &styleName) {
695 if (registeredFamilies.contains(familyName))
697 registeredFamilies.insert(familyName);
699 qCDebug(lcQpaFonts) <<
"Registering font family" << familyName;
700 registerFontFamily(familyName);
701 m_populatedFonts.insert(familyName, *fontFamily);
702 fontFamily->AddRef();
704 if (familyName == defaultFontName
705 && defaultFontName != systemDefaultFontName) {
706 qCDebug(lcQpaFonts) <<
"Adding default font" << systemDefaultFontName
707 <<
"as alternative to" << familyName;
709 m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
710 fontFamily->AddRef();
714 QString defaultLocaleName;
715 QString englishLocaleName;
716 DirectWriteScope<IDWriteLocalizedStrings> names;
717 if (SUCCEEDED(fontFamily->GetFamilyNames(&names))) {
718 if (hasDefaultLocale)
719 defaultLocaleName = localeString(*names, defaultLocale);
720 englishLocaleName = localeString(*names, englishLocale);
724 if (!defaultLocaleName.isEmpty())
725 registerFamily(defaultLocaleName, QString{});
729 if (!englishLocaleName.isEmpty())
730 registerFamily(englishLocaleName, QString{});
733 for (uint j = 0; j < fontFamily->GetFontCount(); ++j) {
734 DirectWriteScope<IDWriteFont3> font;
735 if (SUCCEEDED(fontFamily->GetFont(j, &font))) {
736 collectAdditionalNames(*font,
737 hasDefaultLocale ? defaultLocale :
nullptr,
748 HDC dummy = GetDC(0);
750 lf.lfCharSet = DEFAULT_CHARSET;
751 lf.lfFaceName[0] = 0;
752 lf.lfPitchAndFamily = 0;
753 EnumFontFamiliesEx(dummy, &lf, populateBitmapFonts,
reinterpret_cast<intptr_t>(
this), 0);