8#include <QtCore/qendian.h>
9#include <QtCore/qfile.h>
10#include <QtCore/qstringbuilder.h>
11#include <QtCore/qvarlengtharray.h>
49 qCDebug(lcQpaFonts) <<
"Creating DirectWrite database";
54 for (
auto it = m_populatedFonts.
begin();
it != m_populatedFonts.
end(); ++
it)
55 it.value()->Release();
58QString QWindowsDirectWriteFontDatabase::localeString(IDWriteLocalizedStrings *
names,
63 if (SUCCEEDED(
names->FindLocaleName(localeName, &
index, &exists)) && exists) {
108 auto it = m_populatedFonts.
find(familyName);
109 if (
it == m_populatedFonts.
end() && m_populatedBitmapFonts.
contains(familyName)) {
110 qCDebug(lcQpaFonts) <<
"Populating bitmap font" << 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";
129 const bool scalable =
true;
130 const bool antialias =
false;
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) {
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";
148 QString defaultLocaleFamilyName;
149 QString englishLocaleFamilyName;
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);
160 if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty())
161 englishLocaleFamilyName = familyName;
164 DirectWriteScope<IDWriteLocalizedStrings>
names;
165 if (SUCCEEDED(font1->GetFaceNames(&
names))) {
166 QString defaultLocaleStyleName = hasDefaultLocale ? localeString(*
names, defaultLocale) :
QString();
167 QString englishLocaleStyleName = localeString(*
names, englishLocale);
172 bool fixed = font1->IsMonospacedFont();
174 qCDebug(lcQpaFonts) <<
"Family" << familyName <<
"has english variant" << englishLocaleStyleName <<
", in default locale:" << defaultLocaleStyleName << stretch << style <<
weight << fixed;
176 DirectWriteScope<IDWriteFontFace>
face;
177 if (SUCCEEDED(
font->CreateFontFace(&
face))) {
180 if (!englishLocaleStyleName.isEmpty() || defaultLocaleStyleName.isEmpty()) {
181 qCDebug(lcQpaFonts) <<
"Font" << englishLocaleFamilyName << englishLocaleStyleName <<
"supports writing systems:" << writingSystems;
184 englishLocaleStyleName,
197 if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) {
199 defaultLocaleStyleName,
224 DirectWriteScope<IDWriteFontFace1> face1;
225 if (SUCCEEDED(
face->QueryInterface(__uuidof(IDWriteFontFace1),
226 reinterpret_cast<void **
>(&face1)))) {
227 const void *tableData =
nullptr;
229 void *tableContext =
nullptr;
236 if (SUCCEEDED(hr) && exists) {
240 hr = face1->GetUnicodeRanges(0,
nullptr, &rangeCount);
242 if (rangeCount > 0) {
243 QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount);
245 hr = face1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount);
247 for (
uint i = 0;
i < rangeCount; ++
i) {
248 QChar::Script script = QChar::script(ranges.at(
i).first);
263 return writingSystems;
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.";
278 memset(&lf, 0,
sizeof(LOGFONT));
279 memcpy(lf.lfFaceName, missingFamily.utf16(), missingFamily.size() *
sizeof(
wchar_t));
281 HFONT hfont = CreateFontIndirect(&lf);
283 HDC dummy = GetDC(0);
284 HGDIOBJ oldFont = SelectObject(dummy, hfont);
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))) {
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);
304 bool fixed = font1->IsMonospacedFont();
308 qCDebug(lcQpaFonts) <<
"Registering legacy font family" << missingFamily;
310 englishLocaleStyleName,
320 new FontHandle(*directWriteFontFace, missingFamily));
322 SelectObject(dummy, oldFont);
332 SelectObject(dummy, oldFont);
353 if (
face ==
nullptr) {
354 qCDebug(lcQpaFonts) <<
"Falling back to GDI";
358 DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
360 DirectWriteScope<IDWriteFontFace3> face3;
361 if (SUCCEEDED(
face->QueryInterface(__uuidof(IDWriteFontFace3),
362 reinterpret_cast<void **
>(&face3)))) {
364 simulations |= DWRITE_FONT_SIMULATIONS_BOLD;
367 simulations |= DWRITE_FONT_SIMULATIONS_OBLIQUE;
371 DirectWriteScope<IDWriteFontFace5> newFace;
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);
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))) {
392 if (SUCCEEDED(
font->CreateFontFace(simulations,
398 qCWarning(lcQpaFonts) <<
"DirectWrite: Can't create font face for variable axis values";
417 qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint
427 if (loadedData.isEmpty()) {
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.";
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";
450 const bool scalable =
true;
451 const bool antialias =
false;
455 DirectWriteScope<IDWriteFontFace3> face3;
456 if (SUCCEEDED(
face->QueryInterface(__uuidof(IDWriteFontFace3),
457 reinterpret_cast<void **
>(&face3)))) {
458 QString defaultLocaleFamilyName;
459 QString englishLocaleFamilyName;
461 IDWriteLocalizedStrings *
names =
nullptr;
462 if (SUCCEEDED(face3->GetFamilyNames(&
names))) {
463 defaultLocaleFamilyName = hasDefaultLocale ? localeString(
names, defaultLocale) :
QString();
464 englishLocaleFamilyName = localeString(
names, englishLocale);
469 QString defaultLocaleStyleName;
470 QString englishLocaleStyleName;
471 if (SUCCEEDED(face3->GetFaceNames(&
names))) {
472 defaultLocaleStyleName = hasDefaultLocale ? localeString(
names, defaultLocale) :
QString();
473 englishLocaleStyleName = localeString(
names, englishLocale);
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);
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);
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);
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);
518 bool fixed = face3->IsMonospacedFont();
520 qCDebug(lcQpaFonts) <<
"\tFont names:" << englishLocaleFamilyName <<
", " << defaultLocaleFamilyName
521 <<
", style names:" << englishLocaleStyleName <<
", " << defaultLocaleStyleName
522 <<
", stretch:" << stretch
523 <<
", style:" << style
525 <<
", fixed:" << fixed;
527 if (!englishLocaleFamilyName.isEmpty()) {
528 if (applicationFont !=
nullptr) {
532 properties.familyName = englishLocaleFamilyName;
533 properties.styleName = englishLocaleStyleName;
534 applicationFont->properties.append(
properties);
537 ret.insert(englishLocaleFamilyName);
539 englishLocaleStyleName,
552 if (!defaultLocaleFamilyName.isEmpty() && !
ret.contains(defaultLocaleFamilyName)) {
553 if (applicationFont !=
nullptr) {
557 properties.familyName = englishLocaleFamilyName;
558 properties.styleName = englishLocaleStyleName;
559 applicationFont->properties.append(
properties);
562 ret.insert(defaultLocaleFamilyName);
564 defaultLocaleStyleName,
577 if (!englishLocaleGdiCompatibleFamilyName.isEmpty() &&
578 !
ret.contains(englishLocaleGdiCompatibleFamilyName)) {
579 if (applicationFont !=
nullptr) {
583 properties.familyName = englishLocaleGdiCompatibleFamilyName;
584 applicationFont->properties.append(
properties);
587 ret.insert(englishLocaleGdiCompatibleFamilyName);
589 englishLocaleGdiCompatibleStyleName,
602 if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
603 && !
ret.contains(defaultLocaleGdiCompatibleFamilyName)) {
604 if (applicationFont !=
nullptr) {
608 properties.familyName = defaultLocaleGdiCompatibleFamilyName;
609 applicationFont->properties.append(
properties);
612 ret.insert(defaultLocaleGdiCompatibleFamilyName);
614 defaultLocaleGdiCompatibleStyleName,
627 if (!englishLocaleTypographicFamilyName.isEmpty()
628 && !
ret.contains(englishLocaleTypographicFamilyName)) {
629 if (applicationFont !=
nullptr) {
633 properties.familyName = englishLocaleTypographicFamilyName;
634 applicationFont->properties.append(
properties);
637 ret.insert(englishLocaleTypographicFamilyName);
639 englishLocaleTypographicStyleName,
652 if (!defaultLocaleTypographicFamilyName.isEmpty()
653 && !
ret.contains(defaultLocaleTypographicFamilyName)) {
654 if (applicationFont !=
nullptr) {
658 properties.familyName = defaultLocaleTypographicFamilyName;
659 applicationFont->properties.append(
properties);
662 ret.insert(defaultLocaleTypographicFamilyName);
664 defaultLocaleTypographicStyleName,
678 qCWarning(lcQpaFonts) <<
"Unable to query IDWriteFontFace3 interface from font face.";
694 const TEXTMETRIC *textmetric,
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)) {
705 if (
type & RASTER_FONTTYPE ||
type == 0) {
707 if (!
db->hasPopulatedFont(faceName)) {
708 db->registerFontFamily(faceName);
709 db->registerBitmapFont(faceName);
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";
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.";
733 if (SUCCEEDED(factory6->GetSystemFontCollection(
false,
734 DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
736 for (
uint i = 0;
i < fontCollection->GetFontFamilyCount(); ++
i) {
737 DirectWriteScope<IDWriteFontFamily2> fontFamily;
738 if (SUCCEEDED(fontCollection->GetFontFamily(
i, &fontFamily))) {
742 DirectWriteScope<IDWriteLocalizedStrings>
names;
743 if (SUCCEEDED(fontFamily->GetFamilyNames(&
names))) {
744 if (hasDefaultLocale)
745 defaultLocaleName = localeString(*
names, defaultLocale);
747 englishLocaleName = localeString(*
names, englishLocale);
750 qCDebug(lcQpaFonts) <<
"Registering font, english name = " << englishLocaleName <<
", name in current locale = " << defaultLocaleName;
751 if (!defaultLocaleName.isEmpty()) {
753 m_populatedFonts.
insert(defaultLocaleName, *fontFamily);
754 fontFamily->AddRef();
756 if (defaultLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
757 qDebug(lcQpaFonts) <<
"Adding default font" << systemDefaultFontName <<
"as alternative to" << defaultLocaleName;
759 m_populatedFonts.
insert(systemDefaultFontName, *fontFamily);
760 fontFamily->AddRef();
764 if (!englishLocaleName.isEmpty() && englishLocaleName != defaultLocaleName) {
766 m_populatedFonts.
insert(englishLocaleName, *fontFamily);
767 fontFamily->AddRef();
769 if (englishLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
770 qDebug(lcQpaFonts) <<
"Adding default font" << systemDefaultFontName <<
"as alternative to" << englishLocaleName;
772 m_populatedFonts.
insert(systemDefaultFontName, *fontFamily);
773 fontFamily->AddRef();
782 HDC dummy = GetDC(0);
784 lf.lfCharSet = DEFAULT_CHARSET;
785 lf.lfFaceName[0] = 0;
786 lf.lfPitchAndFamily = 0;
799 QSharedPointer<QWindowsFontEngineData> fontEngineData =
data();
800 DirectWriteScope<IDWriteFactory5> factory5;
801 if (SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
802 reinterpret_cast<void **
>(&factory5)))) {
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
WritingSystem
\value Any \value Latin \value Greek \value Cyrillic \value Armenian \value Hebrew \value Arabic \val...
StyleHint
Style hints are used by the \l{QFont}{font matching} algorithm to find an appropriate default family ...
QStringList families() const
Stretch
Predefined stretch values that follow the CSS naming convention.
Weight
Qt uses a weighting scale from 1 to 1000 compatible with OpenType.
Style
This enum describes the different styles of glyphs that are used to display text.
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
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
bool contains(const Key &key) const
bool contains(const T &value) const
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
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
QWindowsDirectWriteFontDatabase()
~QWindowsDirectWriteFontDatabase() 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(),...
friend class QWindowsFontEngineDirectWrite
bool isPrivateFontFamily(const QString &family) const override
Returns true if the font family is private.
static QFont systemDefaultFont()
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 int defaultVerticalDPI()
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.
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)
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 qCWarning(category,...)
#define qCDebug(category,...)
GLuint64 GLenum void * handle
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLuint GLfloat weight
GLenum GLsizeiptr const void * fontData
#define QStringLiteral(str)
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)
DirectWriteScope(T *res=nullptr)
QMap< QFont::Tag, float > variableAxisValues
The QFont::Tag type provides access to advanced font features.
IDWriteFontFace * fontFace