106void QWindowsDirectWriteFontDatabase::populateFamily(
const QString &familyName)
108 auto it = m_populatedFonts.find(familyName);
109 if (it == m_populatedFonts.end() && m_populatedBitmapFonts.contains(familyName)) {
110 qCDebug(lcQpaFonts) <<
"Populating bitmap font" << familyName;
111 QWindowsFontDatabase::populateFamily(familyName);
115 IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() :
nullptr;
116 if (fontFamily ==
nullptr) {
117 qCWarning(lcQpaFonts) <<
"Cannot find" << familyName <<
"in list of fonts";
121 qCDebug(lcQpaFonts) <<
"Populate family:" << familyName;
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";
127 static const int SMOOTH_SCALABLE = 0xffff;
128 const QString foundryName;
129 const bool scalable =
true;
130 const bool antialias =
false;
131 const int size = SMOOTH_SCALABLE;
133 DirectWriteScope<IDWriteFontList> matchingFonts;
134 if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR,
135 DWRITE_FONT_STRETCH_NORMAL,
136 DWRITE_FONT_STYLE_NORMAL,
138 for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) {
139 DirectWriteScope<IDWriteFont> font;
140 if (SUCCEEDED(matchingFonts->GetFont(j, &font))) {
141 DirectWriteScope<IDWriteFont2> font2;
142 if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont2),
143 reinterpret_cast<
void **>(&font2)))) {
144 qCWarning(lcQpaFonts) <<
"COM object does not support IDWriteFont1";
148 QString defaultLocaleFamilyName;
149 QString englishLocaleFamilyName;
150 QString defaultLocaleGdiCompatibleFamilyName;
151 QString englishLocaleGdiCompatibleFamilyName;
153 DirectWriteScope<IDWriteFontFamily> fontFamily2;
154 if (SUCCEEDED(font2->GetFontFamily(&fontFamily2))) {
155 DirectWriteScope<IDWriteLocalizedStrings> names;
156 if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) {
157 defaultLocaleFamilyName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
158 englishLocaleFamilyName = localeString(*names, englishLocale);
162 if (SUCCEEDED(font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &ok)) && ok) {
163 defaultLocaleGdiCompatibleFamilyName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
164 englishLocaleGdiCompatibleFamilyName = localeString(*names, englishLocale);
168 if (defaultLocaleFamilyName.isEmpty()
169 && englishLocaleFamilyName.isEmpty()
170 && englishLocaleGdiCompatibleFamilyName.isEmpty()
171 && defaultLocaleGdiCompatibleFamilyName.isEmpty()) {
172 englishLocaleFamilyName = familyName;
175 QFont::Stretch stretch = fromDirectWriteStretch(font2->GetStretch());
176 QFont::Style style = fromDirectWriteStyle(font2->GetStyle());
177 QFont::Weight weight = fromDirectWriteWeight(font2->GetWeight());
178 bool fixed = font2->IsMonospacedFont();
179 bool color = font2->IsColorFont();
181 DirectWriteScope<IDWriteFontFace> face;
182 if (SUCCEEDED(font->CreateFontFace(&face))) {
183 QSupportedWritingSystems writingSystems = supportedWritingSystems(*face);
185 auto registerFontName = [&face,
196 (
const QString &rFamilyName,
const QString &rStyleName) {
197 qCDebug(lcQpaFonts) <<
"Family" << familyName <<
"has variant"
198 << rFamilyName <<
", "
199 << rStyleName <<
", "
205 QPlatformFontDatabase::registerFont(rFamilyName,
217 new FontHandle(*face, rFamilyName));
221 DirectWriteScope<IDWriteLocalizedStrings> names;
222 if (SUCCEEDED(font2->GetFaceNames(&names))) {
223 QString defaultLocaleStyleName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
224 QString englishLocaleStyleName = localeString(*names, englishLocale);
225 qCDebug(lcQpaFonts) <<
">>> Storing English locale names";
226 registerFontName(englishLocaleFamilyName, englishLocaleStyleName);
230 if (!defaultLocaleFamilyName.isEmpty()
231 && defaultLocaleFamilyName != englishLocaleFamilyName) {
232 qCDebug(lcQpaFonts) <<
">>> Storing default locale names";
233 registerFontName(defaultLocaleFamilyName, defaultLocaleStyleName);
238 if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
239 || !englishLocaleGdiCompatibleFamilyName.isEmpty()) {
240 QString defaultLocaleGdiCompatibleStyleName;
241 QString englishLocaleGdiCompatibleStyleName;
243 DirectWriteScope<IDWriteLocalizedStrings> names;
245 if (SUCCEEDED(font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, &names, &ok)) && ok) {
246 defaultLocaleGdiCompatibleStyleName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
247 englishLocaleGdiCompatibleStyleName = localeString(*names, englishLocale);
249 if (!englishLocaleGdiCompatibleFamilyName.isEmpty()
250 && englishLocaleGdiCompatibleFamilyName != englishLocaleFamilyName) {
251 qCDebug(lcQpaFonts) <<
">>> Storing English GDI compatible names";
252 registerFontName(englishLocaleGdiCompatibleFamilyName,
253 englishLocaleGdiCompatibleStyleName);
256 if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
257 && defaultLocaleGdiCompatibleFamilyName != englishLocaleGdiCompatibleFamilyName
258 && defaultLocaleGdiCompatibleFamilyName != defaultLocaleFamilyName) {
259 qCDebug(lcQpaFonts) <<
">>> Storing Default locale GDI compatible names";
260 registerFontName(defaultLocaleGdiCompatibleFamilyName,
261 defaultLocaleGdiCompatibleStyleName);
332QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(
const QFontDef &fontDef,
void *handle)
334 const FontHandle *fontHandle =
static_cast<
const FontHandle *>(handle);
335 IDWriteFontFace *face = fontHandle->fontFace;
336 if (face ==
nullptr) {
337 qCDebug(lcQpaFonts) <<
"Falling back to GDI";
338 return QWindowsFontDatabase::fontEngine(fontDef, handle);
341 DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
342 if (fontDef.weight >= QFont::DemiBold || fontDef.style != QFont::StyleNormal) {
343 DirectWriteScope<IDWriteFontFace3> face3;
344 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
345 reinterpret_cast<
void **>(&face3)))) {
346 if (fontDef.weight >= QFont::DemiBold && face3->GetWeight() < DWRITE_FONT_WEIGHT_DEMI_BOLD)
347 simulations |= DWRITE_FONT_SIMULATIONS_BOLD;
349 if (fontDef.style != QFont::StyleNormal && face3->GetStyle() == DWRITE_FONT_STYLE_NORMAL)
350 simulations |= DWRITE_FONT_SIMULATIONS_OBLIQUE;
354 DirectWriteScope<IDWriteFontFace5> newFace;
355 if (!fontDef.variableAxisValues.isEmpty() || simulations != DWRITE_FONT_SIMULATIONS_NONE) {
356 DirectWriteScope<IDWriteFontFace5> face5;
357 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace5),
358 reinterpret_cast<
void **>(&face5)))) {
359 DirectWriteScope<IDWriteFontResource> font;
360 if (SUCCEEDED(face5->GetFontResource(&font))) {
361 UINT32 fontAxisCount = font->GetFontAxisCount();
362 QVarLengthArray<DWRITE_FONT_AXIS_VALUE, 8> fontAxisValues(fontAxisCount);
364 if (!fontDef.variableAxisValues.isEmpty()) {
365 if (SUCCEEDED(face5->GetFontAxisValues(fontAxisValues.data(), fontAxisCount))) {
366 for (UINT32 i = 0; i < fontAxisCount; ++i) {
367 if (
auto maybeTag = QFont::Tag::fromValue(qToBigEndian<UINT32>(fontAxisValues[i].axisTag))) {
368 if (fontDef.variableAxisValues.contains(*maybeTag))
369 fontAxisValues[i].value = fontDef.variableAxisValues.value(*maybeTag);
375 if (SUCCEEDED(font->CreateFontFace(simulations,
376 !fontDef.variableAxisValues.isEmpty() ? fontAxisValues.data() :
nullptr,
377 !fontDef.variableAxisValues.isEmpty() ? fontAxisCount : 0,
381 qCWarning(lcQpaFonts) <<
"DirectWrite: Can't create font face for variable axis values";
387 QWindowsFontEngineDirectWrite *fontEngine =
new QWindowsFontEngineDirectWrite(face, fontDef.pixelSize, data());
388 fontEngine->initFontInfo(fontDef, defaultVerticalDPI());
482QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(
const QByteArray &fontData,
const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont)
484 qCDebug(lcQpaFonts) <<
"Adding application font" << fileName;
486 QByteArray loadedData = fontData;
487 if (loadedData.isEmpty()) {
488 QFile file(fileName);
489 if (!file.open(QIODevice::ReadOnly)) {
490 qCWarning(lcQpaFonts) <<
"Cannot open" << fileName <<
"for reading.";
491 return QStringList();
493 loadedData = file.readAll();
496 QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData, fileName);
497 if (faces.isEmpty()) {
498 qCWarning(lcQpaFonts) <<
"Failed to create DirectWrite face from font data. Font may be unsupported.";
499 return QStringList();
502 QSet<std::pair<QString, QString> > registeredFonts;
504 for (
int i = 0; i < faces.size(); ++i) {
505 IDWriteFontFace *face = faces.at(i);
506 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
507 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
508 wchar_t englishLocale[] = L"en-us";
510 static const int SMOOTH_SCALABLE = 0xffff;
511 const bool scalable =
true;
512 const bool antialias =
false;
513 const int size = SMOOTH_SCALABLE;
515 QSupportedWritingSystems writingSystems = supportedWritingSystems(face);
516 DirectWriteScope<IDWriteFontFace3> face3;
517 if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
518 reinterpret_cast<
void **>(&face3)))) {
520 QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch());
521 QFont::Style style = fromDirectWriteStyle(face3->GetStyle());
522 QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight());
523 bool fixed = face3->IsMonospacedFont();
524 bool color = face3->IsColorFont();
526 auto registerFamilyAndStyle = [&](
const std::pair<QString, QString> &familyAndStyle)
528 if (registeredFonts.contains(familyAndStyle))
530 registeredFonts.insert(familyAndStyle);
531 ret.insert(familyAndStyle.first);
533 qCDebug(lcQpaFonts) <<
"\tRegistering alternative:" << familyAndStyle.first
534 <<
":" << familyAndStyle.second;
535 if (applicationFont !=
nullptr) {
536 QFontDatabasePrivate::ApplicationFont::Properties properties;
537 properties.style = style;
538 properties.weight = weight;
539 properties.familyName = familyAndStyle.first;
540 properties.styleName = familyAndStyle.second;
541 applicationFont->properties.append(properties);
544 QPlatformFontDatabase::registerFont(familyAndStyle.first,
545 familyAndStyle.second,
556 new FontHandle(face, familyAndStyle.first));
559 QString defaultLocaleFamilyName;
560 QString englishLocaleFamilyName;
562 IDWriteLocalizedStrings *names =
nullptr;
563 if (SUCCEEDED(face3->GetFamilyNames(&names))) {
564 defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
565 englishLocaleFamilyName = localeString(names, englishLocale);
570 QString defaultLocaleStyleName;
571 QString englishLocaleStyleName;
572 if (SUCCEEDED(face3->GetFaceNames(&names))) {
573 defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
574 englishLocaleStyleName = localeString(names, englishLocale);
579 qCDebug(lcQpaFonts) <<
"\tFont names:" << englishLocaleFamilyName <<
", " << defaultLocaleFamilyName
580 <<
", style names:" << englishLocaleStyleName <<
", " << defaultLocaleStyleName
581 <<
", stretch:" << stretch
582 <<
", style:" << style
583 <<
", weight:" << weight
584 <<
", fixed:" << fixed;
587 const auto key = std::make_pair(englishLocaleFamilyName, englishLocaleStyleName);
588 if (!englishLocaleFamilyName.isEmpty())
589 registerFamilyAndStyle(key);
593 const auto key = std::make_pair(defaultLocaleFamilyName, defaultLocaleStyleName);
594 if (!defaultLocaleFamilyName.isEmpty())
595 registerFamilyAndStyle(key);
598 collectAdditionalNames(*face3,
599 hasDefaultLocale ? defaultLocale :
nullptr,
601 registerFamilyAndStyle);
604 qCWarning(lcQpaFonts) <<
"Unable to query IDWriteFontFace3 interface from font face.";
642void QWindowsDirectWriteFontDatabase::populateFontDatabase()
644 wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
645 bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
646 wchar_t englishLocale[] = L"en-us";
648 const QString defaultFontName = defaultFont().families().constFirst();
649 const QString systemDefaultFontName = systemDefaultFont().families().constFirst();
651 DirectWriteScope<IDWriteFontCollection2> fontCollection;
652 DirectWriteScope<IDWriteFactory6> factory6;
653 if (FAILED(data()->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory6),
654 reinterpret_cast<
void **>(&factory6)))) {
655 qCWarning(lcQpaFonts) <<
"Can't initialize IDWriteFactory6. Use GDI font engine instead.";
659 if (SUCCEEDED(factory6->GetSystemFontCollection(
false,
660 DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
662 QSet<QString> registeredFamilies;
663 for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) {
664 DirectWriteScope<IDWriteFontFamily2> fontFamily;
665 if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) {
666 auto registerFamily = [&](
const std::pair<QString, QString> &familyAndStyle) {
667 const QString registeredFamily = familyAndStyle.first;
668 if (registeredFamilies.contains(registeredFamily))
670 registeredFamilies.insert(registeredFamily);
672 qCDebug(lcQpaFonts) <<
"Registering font family" << registeredFamily;
673 registerFontFamily(registeredFamily);
674 m_populatedFonts.insert(registeredFamily, *fontFamily);
675 fontFamily->AddRef();
677 if (registeredFamily == defaultFontName
678 && defaultFontName != systemDefaultFontName) {
679 qCDebug(lcQpaFonts) <<
"Adding default font" << systemDefaultFontName
680 <<
"as alternative to" << registeredFamily;
682 m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
683 fontFamily->AddRef();
687 QString defaultLocaleName;
688 QString englishLocaleName;
689 DirectWriteScope<IDWriteLocalizedStrings> names;
690 if (SUCCEEDED(fontFamily->GetFamilyNames(&names))) {
691 if (hasDefaultLocale)
692 defaultLocaleName = localeString(*names, defaultLocale);
693 englishLocaleName = localeString(*names, englishLocale);
697 const auto key = std::make_pair(defaultLocaleName, QString{});
698 if (!defaultLocaleName.isEmpty())
703 const auto key = std::make_pair(englishLocaleName, QString{});
704 if (!englishLocaleName.isEmpty())
708 for (uint j = 0; j < fontFamily->GetFontCount(); ++j) {
709 DirectWriteScope<IDWriteFont3> font;
710 if (SUCCEEDED(fontFamily->GetFont(j, &font))) {
711 collectAdditionalNames(*font,
712 hasDefaultLocale ? defaultLocale :
nullptr,
723 HDC dummy = GetDC(0);
725 lf.lfCharSet = DEFAULT_CHARSET;
726 lf.lfFaceName[0] = 0;
727 lf.lfPitchAndFamily = 0;
728 EnumFontFamiliesEx(dummy, &lf, populateBitmapFonts,
reinterpret_cast<intptr_t>(
this), 0);