summaryrefslogtreecommitdiffstats
path: root/src/gui/text/windows
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/windows')
-rw-r--r--src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp701
-rw-r--r--src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h24
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase.cpp205
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_ft.cpp19
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_ft_p.h3
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_p.h15
-rw-r--r--src/gui/text/windows/qwindowsfontdatabasebase.cpp240
-rw-r--r--src/gui/text/windows/qwindowsfontdatabasebase_p.h16
-rw-r--r--src/gui/text/windows/qwindowsfontengine.cpp22
-rw-r--r--src/gui/text/windows/qwindowsfontengine_p.h4
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite.cpp201
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite_p.h18
12 files changed, 1096 insertions, 372 deletions
diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
index 6b4933cca7..2e15fbb1ac 100644
--- a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp
@@ -18,6 +18,32 @@ QT_BEGIN_NAMESPACE
// Defined in gui/text/qfontdatabase.cpp
Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script);
+template<typename T>
+struct DirectWriteScope {
+ DirectWriteScope(T *res = nullptr) : m_res(res) {}
+ ~DirectWriteScope() {
+ if (m_res != nullptr)
+ m_res->Release();
+ }
+
+ T **operator&()
+ {
+ return &m_res;
+ }
+
+ T *operator->()
+ {
+ return m_res;
+ }
+
+ T *operator*() {
+ return m_res;
+ }
+
+private:
+ T *m_res;
+};
+
QWindowsDirectWriteFontDatabase::QWindowsDirectWriteFontDatabase()
{
qCDebug(lcQpaFonts) << "Creating DirectWrite database";
@@ -80,6 +106,12 @@ static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style)
void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
{
auto it = m_populatedFonts.find(familyName);
+ if (it == m_populatedFonts.end() && m_populatedBitmapFonts.contains(familyName)) {
+ qCDebug(lcQpaFonts) << "Populating bitmap font" << familyName;
+ QWindowsFontDatabase::populateFamily(familyName);
+ return;
+ }
+
IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr;
if (fontFamily == nullptr) {
qCWarning(lcQpaFonts) << "Cannot find" << familyName << "in list of fonts";
@@ -98,7 +130,7 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
const bool antialias = false;
const int size = SMOOTH_SCALABLE;
- IDWriteFontList *matchingFonts;
+ DirectWriteScope<IDWriteFontList> matchingFonts;
if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STRETCH_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
@@ -106,7 +138,7 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) {
IDWriteFont *font;
if (SUCCEEDED(matchingFonts->GetFont(j, &font))) {
- IDWriteFont1 *font1 = nullptr;
+ DirectWriteScope<IDWriteFont1> font1;
if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1),
reinterpret_cast<void **>(&font1)))) {
qCWarning(lcQpaFonts) << "COM object does not support IDWriteFont1";
@@ -116,27 +148,23 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
QString defaultLocaleFamilyName;
QString englishLocaleFamilyName;
- IDWriteFontFamily *fontFamily2;
+ DirectWriteScope<IDWriteFontFamily> fontFamily2;
if (SUCCEEDED(font1->GetFontFamily(&fontFamily2))) {
- IDWriteLocalizedStrings *names;
+ DirectWriteScope<IDWriteLocalizedStrings> names;
if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) {
- defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- englishLocaleFamilyName = localeString(names, englishLocale);
-
- names->Release();
+ defaultLocaleFamilyName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
+ englishLocaleFamilyName = localeString(*names, englishLocale);
}
-
- fontFamily2->Release();
}
if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty())
englishLocaleFamilyName = familyName;
{
- IDWriteLocalizedStrings *names;
+ DirectWriteScope<IDWriteLocalizedStrings> names;
if (SUCCEEDED(font1->GetFaceNames(&names))) {
- QString defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- QString englishLocaleStyleName = localeString(names, englishLocale);
+ QString defaultLocaleStyleName = hasDefaultLocale ? localeString(*names, defaultLocale) : QString();
+ QString englishLocaleStyleName = localeString(*names, englishLocale);
QFont::Stretch stretch = fromDirectWriteStretch(font1->GetStretch());
QFont::Style style = fromDirectWriteStyle(font1->GetStyle());
@@ -145,77 +173,233 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
qCDebug(lcQpaFonts) << "Family" << familyName << "has english variant" << englishLocaleStyleName << ", in default locale:" << defaultLocaleStyleName << stretch << style << weight << fixed;
- IDWriteFontFace *face = nullptr;
+ DirectWriteScope<IDWriteFontFace> face;
if (SUCCEEDED(font->CreateFontFace(&face))) {
- QSupportedWritingSystems writingSystems;
-
- const void *tableData = nullptr;
- UINT32 tableSize;
- void *tableContext = nullptr;
- BOOL exists;
- HRESULT hr = face->TryGetFontTable(qbswap<quint32>(MAKE_TAG('O','S','/','2')),
- &tableData,
- &tableSize,
- &tableContext,
- &exists);
- if (SUCCEEDED(hr) && exists) {
- writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(tableData), tableSize);
- } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems)
- quint32 rangeCount;
- hr = font1->GetUnicodeRanges(0, nullptr, &rangeCount);
-
- if (rangeCount > 0) {
- QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount);
-
- hr = font1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount);
- if (SUCCEEDED(hr)) {
- for (uint i = 0; i < rangeCount; ++i) {
- QChar::Script script = QChar::script(ranges.at(i).first);
-
- QFontDatabase::WritingSystem writingSystem = qt_writing_system_for_script(script);
-
- if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount)
- writingSystems.setSupported(writingSystem);
- }
- } else {
- const QString errorString = qt_error_string(int(hr));
- qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font" << englishLocaleFamilyName << englishLocaleStyleName << ":" << errorString;
- }
- }
- }
+ QSupportedWritingSystems writingSystems = supportedWritingSystems(*face);
if (!englishLocaleStyleName.isEmpty() || defaultLocaleStyleName.isEmpty()) {
qCDebug(lcQpaFonts) << "Font" << englishLocaleFamilyName << englishLocaleStyleName << "supports writing systems:" << writingSystems;
- QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
+ QPlatformFontDatabase::registerFont(englishLocaleFamilyName,
+ englishLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(*face, englishLocaleFamilyName));
}
if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) {
- QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
+ QPlatformFontDatabase::registerFont(defaultLocaleFamilyName,
+ defaultLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(*face, defaultLocaleFamilyName));
}
-
- face->Release();
}
-
- names->Release();
}
}
+ }
+ }
+ }
+}
- font1->Release();
- font->Release();
+QSupportedWritingSystems QWindowsDirectWriteFontDatabase::supportedWritingSystems(IDWriteFontFace *face) const
+{
+ QSupportedWritingSystems writingSystems;
+ writingSystems.setSupported(QFontDatabase::Any);
+
+ DirectWriteScope<IDWriteFontFace1> face1;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace1),
+ reinterpret_cast<void **>(&face1)))) {
+ const void *tableData = nullptr;
+ UINT32 tableSize;
+ void *tableContext = nullptr;
+ BOOL exists;
+ HRESULT hr = face->TryGetFontTable(qFromBigEndian(QFont::Tag("OS/2").value()),
+ &tableData,
+ &tableSize,
+ &tableContext,
+ &exists);
+ if (SUCCEEDED(hr) && exists) {
+ writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(tableData), tableSize);
+ } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems)
+ quint32 rangeCount;
+ hr = face1->GetUnicodeRanges(0, nullptr, &rangeCount);
+
+ if (rangeCount > 0) {
+ QVarLengthArray<DWRITE_UNICODE_RANGE, QChar::ScriptCount> ranges(rangeCount);
+
+ hr = face1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount);
+ if (SUCCEEDED(hr)) {
+ for (uint i = 0; i < rangeCount; ++i) {
+ QChar::Script script = QChar::script(ranges.at(i).first);
+
+ QFontDatabase::WritingSystem writingSystem = qt_writing_system_for_script(script);
+
+ if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount)
+ writingSystems.setSupported(writingSystem);
+ }
+ } else {
+ const QString errorString = qt_error_string(int(hr));
+ qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font:" << errorString;
+ }
}
}
+ }
+
+ return writingSystems;
+}
+
+bool QWindowsDirectWriteFontDatabase::populateFamilyAliases(const QString &missingFamily)
+{
+ // If the font has not been populated, it is possible this is a legacy font family supported
+ // by GDI. We make an attempt at loading it via GDI and then add this face directly to the
+ // database.
+ if (!missingFamily.isEmpty()
+ && missingFamily.size() < LF_FACESIZE
+ && !m_populatedFonts.contains(missingFamily)
+ && !m_populatedBitmapFonts.contains(missingFamily)) {
+ qCDebug(lcQpaFonts) << "Loading unpopulated" << missingFamily << ". Trying GDI.";
+
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(LOGFONT));
+ memcpy(lf.lfFaceName, missingFamily.utf16(), missingFamily.size() * sizeof(wchar_t));
+
+ HFONT hfont = CreateFontIndirect(&lf);
+ if (hfont) {
+ HDC dummy = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(dummy, hfont);
+
+ DirectWriteScope<IDWriteFontFace> directWriteFontFace;
+ if (SUCCEEDED(data()->directWriteGdiInterop->CreateFontFaceFromHdc(dummy, &directWriteFontFace))) {
+ DirectWriteScope<IDWriteFontCollection> fontCollection;
+ if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) {
+ DirectWriteScope<IDWriteFont> font;
+ if (SUCCEEDED(fontCollection->GetFontFromFontFace(*directWriteFontFace, &font))) {
+
+ DirectWriteScope<IDWriteFont1> font1;
+ if (SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1),
+ reinterpret_cast<void **>(&font1)))) {
+ DirectWriteScope<IDWriteLocalizedStrings> names;
+ if (SUCCEEDED(font1->GetFaceNames(&names))) {
+ wchar_t englishLocale[] = L"en-us";
+ QString englishLocaleStyleName = localeString(*names, englishLocale);
+
+ QFont::Stretch stretch = fromDirectWriteStretch(font1->GetStretch());
+ QFont::Style style = fromDirectWriteStyle(font1->GetStyle());
+ QFont::Weight weight = fromDirectWriteWeight(font1->GetWeight());
+ bool fixed = font1->IsMonospacedFont();
+
+ QSupportedWritingSystems writingSystems = supportedWritingSystems(*directWriteFontFace);
+
+ qCDebug(lcQpaFonts) << "Registering legacy font family" << missingFamily;
+ QPlatformFontDatabase::registerFont(missingFamily,
+ englishLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ false,
+ true,
+ 0xffff,
+ fixed,
+ writingSystems,
+ new FontHandle(*directWriteFontFace, missingFamily));
+
+ SelectObject(dummy, oldFont);
+ DeleteObject(hfont);
+
+ return true;
+ }
+ }
+ }
+ }
+ }
- matchingFonts->Release();
+ SelectObject(dummy, oldFont);
+ DeleteObject(hfont);
+ }
}
+
+ // Skip over implementation in QWindowsFontDatabase
+ return QWindowsFontDatabaseBase::populateFamilyAliases(missingFamily);
+}
+
+QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QByteArray &fontData,
+ qreal pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ // Skip over implementation in QWindowsFontDatabase
+ return QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
}
QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- IDWriteFontFace *face = reinterpret_cast<IDWriteFontFace *>(handle);
- Q_ASSERT(face != nullptr);
+ const FontHandle *fontHandle = static_cast<const FontHandle *>(handle);
+ IDWriteFontFace *face = fontHandle->fontFace;
+ if (face == nullptr) {
+ qCDebug(lcQpaFonts) << "Falling back to GDI";
+ return QWindowsFontDatabase::fontEngine(fontDef, handle);
+ }
+
+ DWRITE_FONT_SIMULATIONS simulations = DWRITE_FONT_SIMULATIONS_NONE;
+ if (fontDef.weight >= QFont::DemiBold || fontDef.style != QFont::StyleNormal) {
+ DirectWriteScope<IDWriteFontFace3> face3;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
+ reinterpret_cast<void **>(&face3)))) {
+ if (fontDef.weight >= QFont::DemiBold && face3->GetWeight() < DWRITE_FONT_WEIGHT_DEMI_BOLD)
+ simulations |= DWRITE_FONT_SIMULATIONS_BOLD;
+
+ if (fontDef.style != QFont::StyleNormal && face3->GetStyle() == DWRITE_FONT_STYLE_NORMAL)
+ simulations |= DWRITE_FONT_SIMULATIONS_OBLIQUE;
+ }
+ }
+
+ DirectWriteScope<IDWriteFontFace5> newFace;
+ if (!fontDef.variableAxisValues.isEmpty() || simulations != DWRITE_FONT_SIMULATIONS_NONE) {
+ DirectWriteScope<IDWriteFontFace5> face5;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace5),
+ reinterpret_cast<void **>(&face5)))) {
+ DirectWriteScope<IDWriteFontResource> font;
+ if (SUCCEEDED(face5->GetFontResource(&font))) {
+ UINT32 fontAxisCount = font->GetFontAxisCount();
+ QVarLengthArray<DWRITE_FONT_AXIS_VALUE, 8> fontAxisValues(fontAxisCount);
+
+ if (!fontDef.variableAxisValues.isEmpty()) {
+ if (SUCCEEDED(face5->GetFontAxisValues(fontAxisValues.data(), fontAxisCount))) {
+ for (UINT32 i = 0; i < fontAxisCount; ++i) {
+ if (auto maybeTag = QFont::Tag::fromValue(qToBigEndian<UINT32>(fontAxisValues[i].axisTag))) {
+ if (fontDef.variableAxisValues.contains(*maybeTag))
+ fontAxisValues[i].value = fontDef.variableAxisValues.value(*maybeTag);
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(font->CreateFontFace(simulations,
+ !fontDef.variableAxisValues.isEmpty() ? fontAxisValues.data() : nullptr,
+ !fontDef.variableAxisValues.isEmpty() ? fontAxisCount : 0,
+ &newFace))) {
+ face = *newFace;
+ } else {
+ qCWarning(lcQpaFonts) << "DirectWrite: Can't create font face for variable axis values";
+ }
+ }
+ }
+ }
QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(face, fontDef.pixelSize, data());
fontEngine->initFontInfo(fontDef, defaultVerticalDPI());
@@ -249,111 +433,255 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray
loadedData = file.readAll();
}
- IDWriteFontFace *face = createDirectWriteFace(loadedData);
- if (face == nullptr) {
+ QList<IDWriteFontFace *> faces = createDirectWriteFaces(loadedData);
+ if (faces.isEmpty()) {
qCWarning(lcQpaFonts) << "Failed to create DirectWrite face from font data. Font may be unsupported.";
return QStringList();
}
- wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
- bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
- wchar_t englishLocale[] = L"en-us";
+ QSet<QString> ret;
+ for (int i = 0; i < faces.size(); ++i) {
+ IDWriteFontFace *face = faces.at(i);
+ wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
+ bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
+ wchar_t englishLocale[] = L"en-us";
+
+ static const int SMOOTH_SCALABLE = 0xffff;
+ const bool scalable = true;
+ const bool antialias = false;
+ const int size = SMOOTH_SCALABLE;
+
+ QSupportedWritingSystems writingSystems = supportedWritingSystems(face);
+ DirectWriteScope<IDWriteFontFace3> face3;
+ if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
+ reinterpret_cast<void **>(&face3)))) {
+ QString defaultLocaleFamilyName;
+ QString englishLocaleFamilyName;
+
+ IDWriteLocalizedStrings *names = nullptr;
+ if (SUCCEEDED(face3->GetFamilyNames(&names))) {
+ defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleFamilyName = localeString(names, englishLocale);
+
+ names->Release();
+ }
- static const int SMOOTH_SCALABLE = 0xffff;
- const QString foundryName; // No such concept.
- const bool scalable = true;
- const bool antialias = false;
- const int size = SMOOTH_SCALABLE;
+ QString defaultLocaleStyleName;
+ QString englishLocaleStyleName;
+ if (SUCCEEDED(face3->GetFaceNames(&names))) {
+ defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleStyleName = localeString(names, englishLocale);
- QSupportedWritingSystems writingSystems;
- writingSystems.setSupported(QFontDatabase::Any);
- writingSystems.setSupported(QFontDatabase::Latin);
+ names->Release();
+ }
- QStringList ret;
- IDWriteFontFace3 *face3 = nullptr;
- if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3),
- reinterpret_cast<void **>(&face3)))) {
- QString defaultLocaleFamilyName;
- QString englishLocaleFamilyName;
+ BOOL ok;
+ QString defaultLocaleGdiCompatibleFamilyName;
+ QString englishLocaleGdiCompatibleFamilyName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleGdiCompatibleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleGdiCompatibleFamilyName = localeString(names, englishLocale);
- IDWriteLocalizedStrings *names;
- if (SUCCEEDED(face3->GetFamilyNames(&names))) {
- defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- englishLocaleFamilyName = localeString(names, englishLocale);
+ names->Release();
+ }
- names->Release();
- }
+ QString defaultLocaleGdiCompatibleStyleName;
+ QString englishLocaleGdiCompatibleStyleName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_WIN32_SUBFAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleGdiCompatibleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleGdiCompatibleStyleName = localeString(names, englishLocale);
- QString defaultLocaleStyleName;
- QString englishLocaleStyleName;
- if (SUCCEEDED(face3->GetFaceNames(&names))) {
- defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
- englishLocaleStyleName = localeString(names, englishLocale);
+ names->Release();
+ }
- names->Release();
- }
+ QString defaultLocaleTypographicFamilyName;
+ QString englishLocaleTypographicFamilyName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_FAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleTypographicFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleTypographicFamilyName = localeString(names, englishLocale);
- QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch());
- QFont::Style style = fromDirectWriteStyle(face3->GetStyle());
- QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight());
- bool fixed = face3->IsMonospacedFont();
-
- qCDebug(lcQpaFonts) << "\tFont names:" << englishLocaleFamilyName << ", " << defaultLocaleFamilyName
- << ", style names:" << englishLocaleStyleName << ", " << defaultLocaleStyleName
- << ", stretch:" << stretch
- << ", style:" << style
- << ", weight:" << weight
- << ", fixed:" << fixed;
-
- if (!englishLocaleFamilyName.isEmpty()) {
- if (applicationFont != nullptr) {
- QFontDatabasePrivate::ApplicationFont::Properties properties;
- properties.style = style;
- properties.weight = weight;
- properties.familyName = englishLocaleFamilyName;
- properties.styleName = englishLocaleStyleName;
- applicationFont->properties.append(properties);
+ names->Release();
}
- ret.append(englishLocaleFamilyName);
- QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
- }
+ QString defaultLocaleTypographicStyleName;
+ QString englishLocaleTypographicStyleName;
+ if (SUCCEEDED(face3->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_TYPOGRAPHIC_SUBFAMILY_NAMES, &names, &ok)) && ok) {
+ defaultLocaleTypographicStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString();
+ englishLocaleTypographicStyleName = localeString(names, englishLocale);
- if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) {
- if (applicationFont != nullptr) {
- QFontDatabasePrivate::ApplicationFont::Properties properties;
- properties.style = style;
- properties.weight = weight;
- properties.familyName = englishLocaleFamilyName;
- properties.styleName = englishLocaleStyleName;
- applicationFont->properties.append(properties);
+ names->Release();
}
- ret.append(defaultLocaleFamilyName);
- QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
- face->AddRef();
- }
+ QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch());
+ QFont::Style style = fromDirectWriteStyle(face3->GetStyle());
+ QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight());
+ bool fixed = face3->IsMonospacedFont();
+
+ qCDebug(lcQpaFonts) << "\tFont names:" << englishLocaleFamilyName << ", " << defaultLocaleFamilyName
+ << ", style names:" << englishLocaleStyleName << ", " << defaultLocaleStyleName
+ << ", stretch:" << stretch
+ << ", style:" << style
+ << ", weight:" << weight
+ << ", fixed:" << fixed;
+
+ if (!englishLocaleFamilyName.isEmpty()) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleFamilyName;
+ properties.styleName = englishLocaleStyleName;
+ applicationFont->properties.append(properties);
+ }
- face3->Release();
- } else {
- qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face.";
- }
+ ret.insert(englishLocaleFamilyName);
+ QPlatformFontDatabase::registerFont(englishLocaleFamilyName,
+ englishLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, englishLocaleFamilyName));
+ }
- face->Release();
+ if (!defaultLocaleFamilyName.isEmpty() && !ret.contains(defaultLocaleFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleFamilyName;
+ properties.styleName = englishLocaleStyleName;
+ applicationFont->properties.append(properties);
+ }
- return ret;
-}
+ ret.insert(defaultLocaleFamilyName);
+ QPlatformFontDatabase::registerFont(defaultLocaleFamilyName,
+ defaultLocaleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, defaultLocaleFamilyName));
+ }
-void QWindowsDirectWriteFontDatabase::releaseHandle(void *handle)
-{
- IDWriteFontFace *face = reinterpret_cast<IDWriteFontFace *>(handle);
- face->Release();
-}
+ if (!englishLocaleGdiCompatibleFamilyName.isEmpty() &&
+ !ret.contains(englishLocaleGdiCompatibleFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleGdiCompatibleFamilyName;
+ applicationFont->properties.append(properties);
+ }
-bool QWindowsDirectWriteFontDatabase::fontsAlwaysScalable() const
-{
- return true;
+ ret.insert(englishLocaleGdiCompatibleFamilyName);
+ QPlatformFontDatabase::registerFont(englishLocaleGdiCompatibleFamilyName,
+ englishLocaleGdiCompatibleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, englishLocaleGdiCompatibleFamilyName));
+ }
+
+ if (!defaultLocaleGdiCompatibleFamilyName.isEmpty()
+ && !ret.contains(defaultLocaleGdiCompatibleFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = defaultLocaleGdiCompatibleFamilyName;
+ applicationFont->properties.append(properties);
+ }
+
+ ret.insert(defaultLocaleGdiCompatibleFamilyName);
+ QPlatformFontDatabase::registerFont(defaultLocaleGdiCompatibleFamilyName,
+ defaultLocaleGdiCompatibleStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, defaultLocaleGdiCompatibleFamilyName));
+ }
+
+ if (!englishLocaleTypographicFamilyName.isEmpty()
+ && !ret.contains(englishLocaleTypographicFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = englishLocaleTypographicFamilyName;
+ applicationFont->properties.append(properties);
+ }
+
+ ret.insert(englishLocaleTypographicFamilyName);
+ QPlatformFontDatabase::registerFont(englishLocaleTypographicFamilyName,
+ englishLocaleTypographicStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, englishLocaleTypographicFamilyName));
+ }
+
+ if (!defaultLocaleTypographicFamilyName.isEmpty()
+ && !ret.contains(defaultLocaleTypographicFamilyName)) {
+ if (applicationFont != nullptr) {
+ QFontDatabasePrivate::ApplicationFont::Properties properties;
+ properties.style = style;
+ properties.weight = weight;
+ properties.familyName = defaultLocaleTypographicFamilyName;
+ applicationFont->properties.append(properties);
+ }
+
+ ret.insert(defaultLocaleTypographicFamilyName);
+ QPlatformFontDatabase::registerFont(defaultLocaleTypographicFamilyName,
+ defaultLocaleTypographicStyleName,
+ QString(),
+ weight,
+ style,
+ stretch,
+ antialias,
+ scalable,
+ size,
+ fixed,
+ writingSystems,
+ new FontHandle(face, defaultLocaleTypographicFamilyName));
+ }
+
+ } else {
+ qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face.";
+ }
+
+ face->Release();
+ }
+
+ return ret.values();
}
bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family) const
@@ -362,62 +690,103 @@ bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family)
return false;
}
+static int QT_WIN_CALLBACK populateBitmapFonts(const LOGFONT *logFont,
+ const TEXTMETRIC *textmetric,
+ DWORD type,
+ LPARAM lparam)
+{
+ Q_UNUSED(textmetric);
+
+ // the "@family" fonts are just the same as "family". Ignore them.
+ const ENUMLOGFONTEX *f = reinterpret_cast<const ENUMLOGFONTEX *>(logFont);
+ const wchar_t *faceNameW = f->elfLogFont.lfFaceName;
+ if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) {
+ const QString faceName = QString::fromWCharArray(faceNameW);
+ if (type & RASTER_FONTTYPE || type == 0) {
+ QWindowsDirectWriteFontDatabase *db = reinterpret_cast<QWindowsDirectWriteFontDatabase *>(lparam);
+ if (!db->hasPopulatedFont(faceName)) {
+ db->registerFontFamily(faceName);
+ db->registerBitmapFont(faceName);
+ }
+ }
+ }
+ return 1; // continue
+}
+
void QWindowsDirectWriteFontDatabase::populateFontDatabase()
{
wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
wchar_t englishLocale[] = L"en-us";
- const QString defaultFontName = defaultFont().families().first();
- const QString systemDefaultFontName = systemDefaultFont().families().first();
+ const QString defaultFontName = defaultFont().families().constFirst();
+ const QString systemDefaultFontName = systemDefaultFont().families().constFirst();
+
+ DirectWriteScope<IDWriteFontCollection2> fontCollection;
+ DirectWriteScope<IDWriteFactory6> factory6;
+ if (FAILED(data()->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory6),
+ reinterpret_cast<void **>(&factory6)))) {
+ qCWarning(lcQpaFonts) << "Can't initialize IDWriteFactory6. Use GDI font engine instead.";
+ return;
+ }
- IDWriteFontCollection *fontCollection;
- if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) {
+ if (SUCCEEDED(factory6->GetSystemFontCollection(false,
+ DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC,
+ &fontCollection))) {
for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) {
- IDWriteFontFamily *fontFamily;
+ DirectWriteScope<IDWriteFontFamily2> fontFamily;
if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) {
QString defaultLocaleName;
QString englishLocaleName;
- IDWriteLocalizedStrings *names;
+ DirectWriteScope<IDWriteLocalizedStrings> names;
if (SUCCEEDED(fontFamily->GetFamilyNames(&names))) {
if (hasDefaultLocale)
- defaultLocaleName = localeString(names, defaultLocale);
+ defaultLocaleName = localeString(*names, defaultLocale);
- englishLocaleName = localeString(names, englishLocale);
+ englishLocaleName = localeString(*names, englishLocale);
}
qCDebug(lcQpaFonts) << "Registering font, english name = " << englishLocaleName << ", name in current locale = " << defaultLocaleName;
if (!defaultLocaleName.isEmpty()) {
registerFontFamily(defaultLocaleName);
- m_populatedFonts.insert(defaultLocaleName, fontFamily);
+ m_populatedFonts.insert(defaultLocaleName, *fontFamily);
fontFamily->AddRef();
if (defaultLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << defaultLocaleName;
- m_populatedFonts.insert(systemDefaultFontName, fontFamily);
+ m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
fontFamily->AddRef();
}
}
if (!englishLocaleName.isEmpty() && englishLocaleName != defaultLocaleName) {
registerFontFamily(englishLocaleName);
- m_populatedFonts.insert(englishLocaleName, fontFamily);
+ m_populatedFonts.insert(englishLocaleName, *fontFamily);
fontFamily->AddRef();
if (englishLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) {
qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << englishLocaleName;
- m_populatedFonts.insert(systemDefaultFontName, fontFamily);
+ m_populatedFonts.insert(systemDefaultFontName, *fontFamily);
fontFamily->AddRef();
}
}
-
- fontFamily->Release();
}
}
}
+
+ // Since bitmap fonts are not supported by DirectWrite, we need to populate these as well
+ {
+ HDC dummy = GetDC(0);
+ LOGFONT lf;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfFaceName[0] = 0;
+ lf.lfPitchAndFamily = 0;
+ EnumFontFamiliesEx(dummy, &lf, populateBitmapFonts, reinterpret_cast<intptr_t>(this), 0);
+ ReleaseDC(0, dummy);
+ }
}
QFont QWindowsDirectWriteFontDatabase::defaultFont() const
@@ -425,4 +794,16 @@ QFont QWindowsDirectWriteFontDatabase::defaultFont() const
return QFont(QStringLiteral("Segoe UI"));
}
+bool QWindowsDirectWriteFontDatabase::supportsVariableApplicationFonts() const
+{
+ QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
+ DirectWriteScope<IDWriteFactory5> factory5;
+ if (SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
+ reinterpret_cast<void **>(&factory5)))) {
+ return true;
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h
index 89b216a239..093c629a16 100644
--- a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h
+++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h
@@ -20,17 +20,18 @@
QT_REQUIRE_CONFIG(directwrite3);
-#include "qwindowsfontdatabasebase_p.h"
+#include "qwindowsfontdatabase_p.h"
#include <QtCore/qloggingcategory.h>
struct IDWriteFactory;
struct IDWriteFont;
+struct IDWriteFont1;
struct IDWriteFontFamily;
struct IDWriteLocalizedStrings;
QT_BEGIN_NAMESPACE
-class Q_GUI_EXPORT QWindowsDirectWriteFontDatabase : public QWindowsFontDatabaseBase
+class Q_GUI_EXPORT QWindowsDirectWriteFontDatabase : public QWindowsFontDatabase
{
Q_DISABLE_COPY_MOVE(QWindowsDirectWriteFontDatabase)
public:
@@ -39,19 +40,34 @@ public:
void populateFontDatabase() override;
void populateFamily(const QString &familyName) override;
+ bool populateFamilyAliases(const QString &missingFamily) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
+ QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override;
QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *font = nullptr) override;
- void releaseHandle(void *handle) override;
QFont defaultFont() const override;
- bool fontsAlwaysScalable() const override;
bool isPrivateFontFamily(const QString &family) const override;
+ bool supportsVariableApplicationFonts() const override;
+
+ void registerBitmapFont(const QString &bitmapFont)
+ {
+ m_populatedBitmapFonts.insert(bitmapFont);
+ }
+
+ bool hasPopulatedFont(const QString &fontFamily) const
+ {
+ return m_populatedFonts.contains(fontFamily);
+ }
private:
+ friend class QWindowsFontEngineDirectWrite;
static QString localeString(IDWriteLocalizedStrings *names, wchar_t localeName[]);
+ QSupportedWritingSystems supportedWritingSystems(IDWriteFontFace *face) const;
+
QHash<QString, IDWriteFontFamily *> m_populatedFonts;
+ QSet<QString> m_populatedBitmapFonts;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp
index b3949402e9..adc06a6c2a 100644
--- a/src/gui/text/windows/qwindowsfontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabase.cpp
@@ -10,7 +10,6 @@
#include <QtGui/QFont>
#include <QtGui/QGuiApplication>
-#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/private/qtgui-config_p.h>
#include <QtCore/qmath.h>
@@ -32,6 +31,8 @@
# include "qwindowsfontenginedirectwrite_p.h"
#endif
+#include <mutex>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -55,7 +56,7 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
return hintingPreference == QFont::PreferNoHinting
|| hintingPreference == QFont::PreferVerticalHinting
- || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting);
+ || (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting);
}
#endif // !QT_NO_DIRECTWRITE
@@ -190,17 +191,6 @@ static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSe
return QFontDatabase::Any;
}
-#ifdef MAKE_TAG
-#undef MAKE_TAG
-#endif
-// GetFontData expects the tags in little endian ;(
-#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
- (((quint32)(ch4)) << 24) | \
- (((quint32)(ch3)) << 16) | \
- (((quint32)(ch2)) << 8) | \
- ((quint32)(ch1)) \
- )
-
bool qt_localizedName(const QString &name)
{
const QChar *c = name.unicode();
@@ -378,7 +368,7 @@ QString qt_getEnglishName(const QString &familyName, bool includeStyle)
HGDIOBJ oldobj = SelectObject( hdc, hfont );
- const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
+ const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
// get the name table
unsigned char *table = 0;
@@ -427,7 +417,7 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
// get the name table
QByteArray table;
- const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e');
+ const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0);
if (bytes != GDI_ERROR) {
table.resize(bytes);
@@ -443,18 +433,6 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
return fontNames;
}
-static QChar *createFontFile(const QString &faceName)
-{
- QChar *faceNamePtr = nullptr;
- if (!faceName.isEmpty()) {
- const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1);
- faceNamePtr = new QChar[nameLength + 1];
- memcpy(static_cast<void *>(faceNamePtr), faceName.data(), sizeof(wchar_t) * nameLength);
- faceNamePtr[nameLength] = u'\0';
- }
- return faceNamePtr;
-}
-
namespace {
struct StoreFontPayload {
StoreFontPayload(const QString &family,
@@ -561,33 +539,35 @@ static bool addFontToDatabase(QString familyName,
writingSystems.setSupported(ws);
}
- // We came here from populating a different font family, so we have
- // to ensure the entire typographic family is populated before we
- // mark it as such inside registerFont()
- if (!subFamilyName.isEmpty()
- && familyName != subFamilyName
- && sfp->populatedFontFamily != familyName
- && !QPlatformFontDatabase::isFamilyPopulated(familyName)) {
- sfp->windowsFontDatabase->populateFamily(familyName);
- }
-
+ const bool wasPopulated = QPlatformFontDatabase::isFamilyPopulated(familyName);
QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
+
// add fonts windows can generate for us:
if (weight <= QFont::DemiBold && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
if (style != QFont::StyleItalic && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight,
- QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
- QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
+
+ // We came here from populating a different font family, so we have
+ // to ensure the entire typographic family is populated before we
+ // mark it as such inside registerFont()
+ if (!subFamilyName.isEmpty()
+ && familyName != subFamilyName
+ && sfp->populatedFontFamily != familyName
+ && !wasPopulated) {
+ sfp->windowsFontDatabase->populateFamily(familyName);
+ }
if (!subFamilyName.isEmpty() && familyName != subFamilyName) {
QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
}
if (!englishName.isEmpty() && englishName != familyName)
@@ -725,7 +705,7 @@ void QWindowsFontDatabase::populateFontDatabase()
EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
ReleaseDC(0, dummy);
// Work around EnumFontFamiliesEx() not listing the system font.
- const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().first();
+ const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst();
if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
QPlatformFontDatabase::registerFontFamily(systemDefaultFamily);
addDefaultEUDCFont();
@@ -733,6 +713,7 @@ void QWindowsFontDatabase::populateFontDatabase()
void QWindowsFontDatabase::invalidate()
{
+ QWindowsFontDatabaseBase::invalidate();
removeApplicationFonts();
}
@@ -758,7 +739,8 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- const QString faceName(static_cast<const QChar*>(handle));
+ FontHandle *fontHandle = static_cast<FontHandle *>(handle);
+ const QString faceName = fontHandle->faceName.left(LF_FACESIZE - 1);
QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
defaultVerticalDPI(),
data());
@@ -820,7 +802,7 @@ QT_WARNING_POP
if (fontEngine) {
if (request.families != fontEngine->fontDef.families) {
qWarning("%s: Failed to load font. Got fallback instead: %s", __FUNCTION__,
- qPrintable(fontEngine->fontDef.families.first()));
+ qPrintable(fontEngine->fontDef.families.constFirst()));
if (fontEngine->ref.loadRelaxed() == 0)
delete fontEngine;
fontEngine = 0;
@@ -844,10 +826,13 @@ QT_WARNING_POP
Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine.");
}
- UniqueFontData uniqueData;
+ UniqueFontData uniqueData{};
uniqueData.handle = fontHandle;
- uniqueData.refCount.ref();
- m_uniqueFontData[uniqueFamilyName] = uniqueData;
+ ++uniqueData.refCount;
+ {
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ m_uniqueFontData[uniqueFamilyName] = uniqueData;
+ }
}
} else {
RemoveFontMemResourceEx(fontHandle);
@@ -868,36 +853,70 @@ QT_WARNING_POP
return fontEngine;
}
-static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
+static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
{
QList<quint32> offsets;
- const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
- if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
- if (headerTag != MAKE_TAG(0, 1, 0, 0)
- && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
- && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
- && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
+ if (fileEndSentinel - fontData < 12) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ return offsets;
+ }
+
+ const quint32 headerTag = qFromUnaligned<quint32>(fontData);
+ if (headerTag != qFromBigEndian(QFont::Tag("ttcf").value())) {
+ if (headerTag != qFromBigEndian(QFont::Tag("\0\1\0\0").value())
+ && headerTag != qFromBigEndian(QFont::Tag("OTTO").value())
+ && headerTag != qFromBigEndian(QFont::Tag("true").value())
+ && headerTag != qFromBigEndian(QFont::Tag("typ1").value())) {
return offsets;
+ }
offsets << 0;
return offsets;
}
+
+ const quint32 maximumNumFonts = 0xffff;
const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
- for (uint i = 0; i < numFonts; ++i) {
- offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+ if (numFonts > maximumNumFonts) {
+ qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting.";
+ return offsets;
+ }
+
+ if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) {
+ for (quint32 i = 0; i < numFonts; ++i)
+ offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
+
return offsets;
}
-static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
+static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
{
- const quint16 numTables = qFromBigEndian<quint16>(data + 4);
- for (uint i = 0; i < numTables; ++i) {
- const quint32 offset = 12 + 16 * i;
- if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
- *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
- *length = qFromBigEndian<quint32>(data + offset + 12);
- return;
+ if (fileEndSentinel - data >= 6) {
+ const quint16 numTables = qFromBigEndian<quint16>(data + 4);
+ if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) {
+ for (quint32 i = 0; i < numTables; ++i) {
+ const quint32 offset = 12 + 16 * i;
+ if (qFromUnaligned<quint32>(data + offset) == tag) {
+ const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8);
+ if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ break;
+ }
+ *table = fileBegin + tableOffset;
+ *length = qFromBigEndian<quint32>(data + offset + 12);
+ if (quintptr(fileEndSentinel - *table) < *length) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ break;
+ }
+ return;
+ }
+ }
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
*table = 0;
*length = 0;
@@ -910,8 +929,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
QList<QFontValues> *values)
{
const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
+ const uchar *dataEndSentinel = data + fontData.size();
- QList<quint32> offsets = getTrueTypeFontOffsets(data);
+ QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
if (offsets.isEmpty())
return;
@@ -919,7 +939,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
const uchar *font = data + offsets.at(i);
const uchar *table;
quint32 length;
- getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
+ getFontTable(data, dataEndSentinel, font,
+ qFromBigEndian(QFont::Tag("name").value()),
+ &table, &length);
if (!table)
continue;
QFontNames names = qt_getCanonicalFontNames(table, length);
@@ -928,8 +950,11 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
families->append(std::move(names));
- if (values || signatures)
- getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
+ if (values || signatures) {
+ getFontTable(data, dataEndSentinel, font,
+ qFromBigEndian(QFont::Tag("OS/2").value()),
+ &table, &length);
+ }
if (values) {
QFontValues fontValues;
@@ -1075,7 +1100,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
void QWindowsFontDatabase::removeApplicationFonts()
{
- for (const WinApplicationFont &font : qAsConst(m_applicationFonts)) {
+ for (const WinApplicationFont &font : std::as_const(m_applicationFonts)) {
if (font.handle) {
RemoveFontMemResourceEx(font.handle);
} else {
@@ -1087,10 +1112,22 @@ void QWindowsFontDatabase::removeApplicationFonts()
m_eudcFonts.clear();
}
+QWindowsFontDatabase::FontHandle::FontHandle(IDWriteFontFace *face, const QString &name)
+ : fontFace(face), faceName(name)
+{
+ fontFace->AddRef();
+}
+
+
+QWindowsFontDatabase::FontHandle::~FontHandle()
+{
+ if (fontFace != nullptr)
+ fontFace->Release();
+}
+
void QWindowsFontDatabase::releaseHandle(void *handle)
{
- const QChar *faceName = reinterpret_cast<const QChar *>(handle);
- delete[] faceName;
+ delete static_cast<FontHandle *>(handle);
}
QString QWindowsFontDatabase::fontDir() const
@@ -1107,18 +1144,22 @@ bool QWindowsFontDatabase::fontsAlwaysScalable() const
void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont)
{
- if (m_uniqueFontData.contains(uniqueFont)) {
- if (!m_uniqueFontData[uniqueFont].refCount.deref()) {
- RemoveFontMemResourceEx(m_uniqueFontData[uniqueFont].handle);
- m_uniqueFontData.remove(uniqueFont);
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ const auto it = m_uniqueFontData.find(uniqueFont);
+ if (it != m_uniqueFontData.end()) {
+ if (--it->refCount == 0) {
+ RemoveFontMemResourceEx(it->handle);
+ m_uniqueFontData.erase(it);
}
}
}
void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
{
- if (m_uniqueFontData.contains(uniqueFont))
- m_uniqueFontData[uniqueFont].refCount.ref();
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ const auto it = m_uniqueFontData.find(uniqueFont);
+ if (it != m_uniqueFontData.end())
+ ++it->refCount;
}
QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
@@ -1186,6 +1227,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace);
if (SUCCEEDED(hr)) {
bool isColorFont = false;
+ bool needsSimulation = false;
#if QT_CONFIG(direct2d)
IDWriteFontFace2 *directWriteFontFace2 = nullptr;
if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2),
@@ -1193,10 +1235,12 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
if (directWriteFontFace2->IsColorFont())
isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0;
+ needsSimulation = directWriteFontFace2->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE;
+
directWriteFontFace2->Release();
}
#endif // direct2d
- useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont);
+ useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont) || needsSimulation;
qCDebug(lcQpaFonts)
<< __FUNCTION__ << request.families.first() << request.pointSize << "pt"
<< "hintingPreference=" << hintingPreference << "color=" << isColorFont
@@ -1212,9 +1256,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
QFontDef fontDef = request;
fontDef.families = QStringList(QString::fromWCharArray(n));
-
- if (isColorFont)
- fedw->glyphFormat = QFontEngine::Format_ARGB;
fedw->initFontInfo(fontDef, dpi);
fe = fedw;
}
diff --git a/src/gui/text/windows/qwindowsfontdatabase_ft.cpp b/src/gui/text/windows/qwindowsfontdatabase_ft.cpp
index f30a39aecc..0604a85e35 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabase_ft.cpp
@@ -295,6 +295,21 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t
return 1;
}
+bool QWindowsFontDatabaseFT::populateFamilyAliases(const QString &missingFamily)
+{
+ Q_UNUSED(missingFamily);
+
+ if (m_hasPopulatedAliases)
+ return false;
+
+ QStringList families = QFontDatabase::families();
+ for (const QString &family : families)
+ populateFamily(family);
+ m_hasPopulatedAliases = true;
+
+ return true;
+}
+
/*
\brief Populates the font database using EnumFontFamiliesEx().
@@ -363,7 +378,7 @@ void QWindowsFontDatabaseFT::populateFontDatabase()
EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
ReleaseDC(0, dummy);
// Work around EnumFontFamiliesEx() not listing the system font
- const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().first();
+ const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst();
if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
QPlatformFontDatabase::registerFontFamily(systemDefaultFamily);
}
@@ -371,7 +386,7 @@ void QWindowsFontDatabaseFT::populateFontDatabase()
QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle)
{
QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontDef, handle);
- qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.families.first() << fe << handle;
+ qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.families.constFirst() << fe << handle;
return fe;
}
diff --git a/src/gui/text/windows/qwindowsfontdatabase_ft_p.h b/src/gui/text/windows/qwindowsfontdatabase_ft_p.h
index b908cd54c6..381a7be4e7 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_ft_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabase_ft_p.h
@@ -25,6 +25,7 @@ class Q_GUI_EXPORT QWindowsFontDatabaseFT : public QFreeTypeFontDatabase
{
public:
void populateFontDatabase() override;
+ bool populateFamilyAliases(const QString &familyName) override;
void populateFamily(const QString &familyName) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize,
@@ -36,6 +37,8 @@ public:
QString fontDir() const override;
QFont defaultFont() const override;
+
+ bool m_hasPopulatedAliases = false;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h
index 923f875336..0c99c91fde 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabase_p.h
@@ -21,6 +21,7 @@
#include <QtCore/QSharedPointer>
#include <QtCore/QLoggingCategory>
#include <QtCore/qhashfunctions.h>
+#include <QtCore/qmutex.h>
#include <QtCore/qt_windows.h>
QT_BEGIN_NAMESPACE
@@ -44,6 +45,7 @@ public:
void populateFontDatabase() override;
void invalidate() override;
+ void removeApplicationFonts();
void populateFamily(const QString &familyName) override;
bool populateFamilyAliases(const QString &missingFamily) override;
@@ -73,8 +75,16 @@ public:
static void debugFormat(QDebug &d, const LOGFONT &lf);
#endif // !QT_NO_DEBUG_STREAM
+ struct FontHandle {
+ FontHandle(const QString &name) : faceName(name) {}
+ FontHandle(IDWriteFontFace *face, const QString &name);
+ ~FontHandle();
+
+ IDWriteFontFace *fontFace = nullptr;
+ QString faceName;
+ };
+
private:
- void removeApplicationFonts();
void addDefaultEUDCFont();
struct WinApplicationFont {
@@ -86,9 +96,10 @@ private:
struct UniqueFontData {
HANDLE handle;
- QAtomicInt refCount;
+ int refCount;
};
+ QMutex m_uniqueFontDataMutex; // protects m_uniqueFontData
QMap<QString, UniqueFontData> m_uniqueFontData;
static unsigned m_fontOptions;
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
index a6df42da95..84e619b0d9 100644
--- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
@@ -359,10 +359,10 @@ namespace {
{
}
- inline void addKey(const void *key, const QByteArray &fontData)
+ inline void addKey(const QByteArray &fontData)
{
- Q_ASSERT(!m_fontDatas.contains(key));
- m_fontDatas.insert(key, fontData);
+ if (!m_fontDatas.contains(fontData.data()))
+ m_fontDatas.insert(fontData.data(), fontData);
}
inline void removeKey(const void *key)
@@ -378,6 +378,11 @@ namespace {
UINT32 fontFileReferenceKeySize,
OUT IDWriteFontFileStream **fontFileStream) override;
+ void clear()
+ {
+ m_fontDatas.clear();
+ }
+
private:
ULONG m_referenceCount;
QHash<const void *, QByteArray> m_fontDatas;
@@ -435,52 +440,62 @@ namespace {
return S_OK;
}
- class CustomFontFileLoader
+} // Anonymous namespace
+
+class QCustomFontFileLoader
+{
+public:
+ QCustomFontFileLoader(IDWriteFactory *factory)
{
- public:
- CustomFontFileLoader(IDWriteFactory *factory)
- {
- m_directWriteFactory = factory;
+ m_directWriteFactory = factory;
- if (m_directWriteFactory) {
- m_directWriteFactory->AddRef();
+ if (m_directWriteFactory) {
+ m_directWriteFactory->AddRef();
- m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
- m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
- }
+ m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
+ m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
}
+ }
- ~CustomFontFileLoader()
- {
- if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
- m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
+ ~QCustomFontFileLoader()
+ {
+ clear();
- if (m_directWriteFactory != nullptr)
- m_directWriteFactory->Release();
- }
+ if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
+ m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
- void addKey(const void *key, const QByteArray &fontData)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->addKey(key, fontData);
- }
+ if (m_directWriteFactory != nullptr)
+ m_directWriteFactory->Release();
+ }
- void removeKey(const void *key)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->removeKey(key);
- }
+ void addKey(const QByteArray &fontData)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->addKey(fontData);
+ }
- IDWriteFontFileLoader *loader() const
- {
- return m_directWriteFontFileLoader;
- }
+ void removeKey(const void *key)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->removeKey(key);
+ }
+
+ IDWriteFontFileLoader *loader() const
+ {
+ return m_directWriteFontFileLoader;
+ }
+
+ void clear()
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->clear();
+ }
+
+private:
+ IDWriteFactory *m_directWriteFactory = nullptr;
+ DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
+};
- private:
- IDWriteFactory *m_directWriteFactory = nullptr;
- DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
- };
-} // Anonymous namespace
#endif // directwrite && direct2d
@@ -550,12 +565,27 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory
IUnknown *result = nullptr;
# if QT_CONFIG(directwrite3)
- DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory6";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result);
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory5";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
+ }
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory3";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
+ }
# endif
- if (result == nullptr)
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory2";
DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
+ }
if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create plain IDWriteFactory";
if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
qErrnoWarning("DWriteCreateFactory failed");
return;
@@ -566,16 +596,9 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory
}
#endif // directwrite && direct2d
-static int s_defaultVerticalDPI = 96; // Native Pixels
-
int QWindowsFontDatabaseBase::defaultVerticalDPI()
{
- return s_defaultVerticalDPI;
-}
-
-void QWindowsFontDatabaseBase::setDefaultVerticalDPI(int d)
-{
- s_defaultVerticalDPI = d;
+ return 96;
}
LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName)
@@ -690,36 +713,55 @@ HFONT QWindowsFontDatabaseBase::systemFont()
QFont QWindowsFontDatabaseBase::systemDefaultFont()
{
// Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610)
- NONCLIENTMETRICS ncm;
- ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
- SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
+ NONCLIENTMETRICS ncm = {};
+ ncm.cbSize = sizeof(ncm);
+ SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI());
const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont;
return systemFont;
}
+void QWindowsFontDatabaseBase::invalidate()
+{
+#if QT_CONFIG(directwrite)
+ m_fontFileLoader.reset(nullptr);
+#endif
+}
+
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
-IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const
+IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData)
+{
+ QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false);
+ Q_ASSERT(faces.size() <= 1);
+
+ return faces.isEmpty() ? nullptr : faces.first();
+}
+
+QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
+ bool queryVariations) const
{
+ QList<IDWriteFontFace *> ret;
QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
if (fontEngineData->directWriteFactory == nullptr) {
qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
- return nullptr;
+ return ret;
}
- CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory);
- fontFileLoader.addKey(this, fontData);
+ if (m_fontFileLoader == nullptr)
+ m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
+
+ m_fontFileLoader->addKey(fontData);
IDWriteFontFile *fontFile = nullptr;
- const void *key = this;
+ const void *key = fontData.data();
HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
sizeof(void *),
- fontFileLoader.loader(),
+ m_fontFileLoader->loader(),
&fontFile);
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
- return nullptr;
+ return ret;
}
BOOL isSupportedFontType;
@@ -729,28 +771,75 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra
fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
if (!isSupportedFontType) {
fontFile->Release();
- return nullptr;
+ return ret;
+ }
+
+#if QT_CONFIG(directwrite3)
+ IDWriteFactory5 *factory5 = nullptr;
+ if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
+ reinterpret_cast<void **>(&factory5)))) {
+
+ IDWriteFontSetBuilder1 *builder;
+ if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
+ if (SUCCEEDED(builder->AddFontFile(fontFile))) {
+ IDWriteFontSet *fontSet;
+ if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
+ int count = fontSet->GetFontCount();
+ qCDebug(lcQpaFonts) << "Found" << count << "variations in font file";
+ for (int i = 0; i < count; ++i) {
+ IDWriteFontFaceReference *ref;
+ if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
+ IDWriteFontFace3 *face;
+ if (SUCCEEDED(ref->CreateFontFace(&face))) {
+ ret.append(face);
+ }
+ ref->Release();
+ }
+ }
+ fontSet->Release();
+ }
+ }
+
+ builder->Release();
+ }
+
+ factory5->Release();
}
+#else
+ Q_UNUSED(queryVariations);
+#endif
// ### Currently no support for .ttc, but we could easily return a list here.
- IDWriteFontFace *directWriteFontFace = nullptr;
- hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
- 1,
- &fontFile,
- 0,
- DWRITE_FONT_SIMULATIONS_NONE,
- &directWriteFontFace);
- if (FAILED(hres)) {
- qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
- fontFile->Release();
- return nullptr;
+ if (ret.isEmpty()) {
+ IDWriteFontFace *directWriteFontFace = nullptr;
+ hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
+ 1,
+ &fontFile,
+ 0,
+ DWRITE_FONT_SIMULATIONS_NONE,
+ &directWriteFontFace);
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
+ fontFile->Release();
+ return ret;
+ } else {
+ ret.append(directWriteFontFace);
+ }
}
fontFile->Release();
- return directWriteFontFace;
+
+ return ret;
}
#endif // directwrite && direct2d
+QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QFontDef &fontDef, void *handle)
+{
+ // This function was apparently not used before, and probably isn't now either,
+ // call the base implementation which just prints that it's not supported.
+ return QPlatformFontDatabase::fontEngine(fontDef, handle);
+}
+
QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
QFontEngine *fontEngine = nullptr;
@@ -760,7 +849,10 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr
if (fontEngineData->directWriteFactory == nullptr)
return nullptr;
- IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData);
+ IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
+ if (directWriteFontFace == nullptr)
+ return nullptr;
+
fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
pixelSize,
fontEngineData);
@@ -802,7 +894,7 @@ QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint)
default:
break;
}
- return QStringLiteral("MS Shell Dlg 2");
+ return QStringLiteral("Tahoma");
}
// Creation functions
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase_p.h b/src/gui/text/windows/qwindowsfontdatabasebase_p.h
index d192c62d7f..55a3363551 100644
--- a/src/gui/text/windows/qwindowsfontdatabasebase_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabasebase_p.h
@@ -29,6 +29,10 @@
QT_BEGIN_NAMESPACE
+#if QT_CONFIG(directwrite)
+ class QCustomFontFileLoader;
+#endif
+
class QWindowsFontEngineData
{
Q_DISABLE_COPY_MOVE(QWindowsFontEngineData)
@@ -53,10 +57,12 @@ public:
QWindowsFontDatabaseBase();
~QWindowsFontDatabaseBase() override;
+ QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
+ void invalidate() override;
+
static int defaultVerticalDPI();
- static void setDefaultVerticalDPI(int d);
static QSharedPointer<QWindowsFontEngineData> data();
#if QT_CONFIG(directwrite)
@@ -91,11 +97,17 @@ public:
protected:
#if QT_CONFIG(directwrite)
- IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData) const;
+ QList<IDWriteFontFace *> createDirectWriteFaces(const QByteArray &fontData,
+ bool queryVariations = true) const;
+ IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData);
#endif
private:
static bool init(QSharedPointer<QWindowsFontEngineData> data);
+
+#if QT_CONFIG(directwrite)
+ mutable std::unique_ptr<QCustomFontFileLoader> m_fontFileLoader;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/text/windows/qwindowsfontengine.cpp b/src/gui/text/windows/qwindowsfontengine.cpp
index 5aef72eab3..5de80dc8a3 100644
--- a/src/gui/text/windows/qwindowsfontengine.cpp
+++ b/src/gui/text/windows/qwindowsfontengine.cpp
@@ -104,7 +104,7 @@ void QWindowsFontEngine::getCMap()
SelectObject(hdc, hfont);
bool symb = false;
if (ttf) {
- cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
+ cmapTable = getSfntTable(QFont::Tag("cmap").value());
cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
cmapTable.size(), &symb, &cmapSize);
}
@@ -132,8 +132,9 @@ void QWindowsFontEngine::getCMap()
}
}
-int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const
+int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const
{
+ *mappedGlyphs = 0;
int glyph_pos = 0;
{
if (symbol) {
@@ -143,6 +144,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000);
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
} else if (ttf) {
@@ -150,6 +153,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
while (it.hasNext()) {
const uint uc = it.next();
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc);
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
} else {
@@ -160,6 +165,8 @@ int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLa
glyphs->glyphs[glyph_pos] = uc;
else
glyphs->glyphs[glyph_pos] = 0;
+ if (glyphs->glyphs[glyph_pos] || isIgnorableChar(uc))
+ (*mappedGlyphs)++;
++glyph_pos;
}
}
@@ -259,7 +266,7 @@ HGDIOBJ QWindowsFontEngine::selectDesignFont() const
return SelectObject(m_fontEngineData->hdc, designFont);
}
-bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
@@ -268,12 +275,13 @@ bool QWindowsFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *g
}
glyphs->numGlyphs = *nglyphs;
- *nglyphs = getGlyphIndexes(str, len, glyphs);
+ int mappedGlyphs;
+ *nglyphs = getGlyphIndexes(str, len, glyphs, &mappedGlyphs);
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return mappedGlyphs;
}
inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width)
@@ -471,7 +479,7 @@ namespace {
QFixed QWindowsFontEngine::capHeight() const
{
- const QByteArray tableData = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ const QByteArray tableData = getSfntTable(QFont::Tag("OS/2").value());
if (size_t(tableData.size()) >= sizeof(OS2Table)) {
const OS2Table *table = reinterpret_cast<const OS2Table *>(tableData.constData());
if (qFromBigEndian<quint16>(table->version) >= 2) {
@@ -1089,7 +1097,7 @@ QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph,
QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
{
QFontDef request = fontDef;
- QString actualFontName = request.families.first();
+ QString actualFontName = request.families.constFirst();
if (!uniqueFamilyName.isEmpty())
request.families = QStringList(uniqueFamilyName);
request.pixelSize = pixelSize;
diff --git a/src/gui/text/windows/qwindowsfontengine_p.h b/src/gui/text/windows/qwindowsfontengine_p.h
index afe8ee4ca5..07f4db3c4a 100644
--- a/src/gui/text/windows/qwindowsfontengine_p.h
+++ b/src/gui/text/windows/qwindowsfontengine_p.h
@@ -48,7 +48,7 @@ public:
QFixed emSquareSize() const override;
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override;
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override;
@@ -88,7 +88,7 @@ public:
bool hasUnreliableGlyphOutline() const override;
- int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const;
+ int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs, int *mappedGlyphs) const;
void getCMap();
bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const;
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
index bc8e0b7ed1..47b8a7ee3c 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
@@ -12,10 +12,14 @@
#include <QtCore/private/qwinregistry_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
-#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/qpainterpath.h>
-#include <dwrite_2.h>
+#if QT_CONFIG(directwrite3)
+# include "qwindowsdirectwritefontdatabase_p.h"
+# include <dwrite_3.h>
+#else
+# include <dwrite_2.h>
+#endif
#include <d2d1.h>
@@ -65,7 +69,7 @@ namespace {
};
void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers,
- UINT bezierCount)
+ UINT bezierCount) noexcept
{
for (uint i=0; i<bezierCount; ++i) {
QPointF c1 = fromD2D1_POINT_2F(beziers[i].point1);
@@ -76,48 +80,48 @@ namespace {
}
}
- void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount)
+ void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) noexcept
{
for (uint i=0; i<pointsCount; ++i)
m_path->lineTo(fromD2D1_POINT_2F(points[i]));
}
void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint,
- D2D1_FIGURE_BEGIN /*figureBegin*/)
+ D2D1_FIGURE_BEGIN /*figureBegin*/) noexcept
{
m_startPoint = fromD2D1_POINT_2F(startPoint);
m_path->moveTo(m_startPoint);
}
- IFACEMETHODIMP GeometrySink::Close()
+ IFACEMETHODIMP GeometrySink::Close() noexcept
{
return E_NOTIMPL;
}
- void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd)
+ void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) noexcept
{
if (figureEnd == D2D1_FIGURE_END_CLOSED)
m_path->closeSubpath();
}
- void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode)
+ void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) noexcept
{
m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE
? Qt::OddEvenFill
: Qt::WindingFill);
}
- void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/)
+ void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/) noexcept
{
/* Not implemented */
}
- IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef()
+ IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef() noexcept
{
return InterlockedIncrement(&m_refCount);
}
- IFACEMETHODIMP_(unsigned long) GeometrySink::Release()
+ IFACEMETHODIMP_(unsigned long) GeometrySink::Release() noexcept
{
unsigned long newCount = InterlockedDecrement(&m_refCount);
if (newCount == 0)
@@ -129,7 +133,7 @@ namespace {
return newCount;
}
- IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject)
+ IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject) noexcept
{
if (__uuidof(IDWriteGeometrySink) == riid) {
*ppvObject = this;
@@ -158,10 +162,13 @@ static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE rende
}
}
-static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef)
+DWRITE_RENDERING_MODE QWindowsFontEngineDirectWrite::hintingPreferenceToRenderingMode(const QFontDef &fontDef) const
{
+ if ((fontDef.styleStrategy & QFont::NoAntialias) && glyphFormat != QFontEngine::Format_ARGB)
+ return DWRITE_RENDERING_MODE_ALIASED;
+
QFont::HintingPreference hintingPreference = QFont::HintingPreference(fontDef.hintingPreference);
- if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting) {
+ if (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting) {
// Microsoft documentation recommends using asymmetric rendering for small fonts
// at pixel size 16 and less, and symmetric for larger fonts.
hintingPreference = fontDef.pixelSize > 16.0
@@ -212,7 +219,7 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di
fontDef.pixelSize = pixelSize;
collectMetrics();
- cache_cost = (m_ascent.toInt() + m_descent.toInt()) * m_xHeight.toInt() * 2000;
+ cache_cost = m_xHeight.toInt() * m_xHeight.toInt() * 2000;
}
QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite()
@@ -354,12 +361,14 @@ void QWindowsFontEngineDirectWrite::collectMetrics()
fontFile->Release();
}
- QByteArray table = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ QByteArray table = getSfntTable(QFont::Tag("hhea").value());
const int advanceWidthMaxLocation = 10;
if (table.size() >= advanceWidthMaxLocation + int(sizeof(quint16))) {
quint16 advanceWidthMax = qFromBigEndian<quint16>(table.constData() + advanceWidthMaxLocation);
m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax);
}
+
+ loadKerningPairs(emSquareSize() / QFixed::fromReal(fontDef.pixelSize));
}
QFixed QWindowsFontEngineDirectWrite::underlinePosition() const
@@ -426,13 +435,13 @@ glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const
return glyphIndex;
}
-bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
- int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
QVarLengthArray<UINT32> codePoints(len);
@@ -446,11 +455,15 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly
glyphIndices.data());
if (FAILED(hr)) {
qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__);
- return false;
+ return -1;
}
- for (int i = 0; i < actualLength; ++i)
+ int mappedGlyphs = 0;
+ for (int i = 0; i < actualLength; ++i) {
glyphs->glyphs[i] = glyphIndices.at(i);
+ if (glyphs->glyphs[i] != 0 || isIgnorableChar(codePoints.at(i)))
+ mappedGlyphs++;
+ }
*nglyphs = actualLength;
glyphs->numGlyphs = actualLength;
@@ -458,7 +471,7 @@ bool QWindowsFontEngineDirectWrite::stringToCMap(const QChar *str, int len, QGly
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, {});
- return true;
+ return mappedGlyphs;
}
QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const
@@ -466,7 +479,7 @@ QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const
return m_faceId;
}
-void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
+void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags shaperFlags) const
{
QVarLengthArray<UINT16> glyphIndices(glyphs->numGlyphs);
@@ -478,11 +491,14 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
HRESULT hr;
DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef);
- if (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL) {
+ bool needsDesignMetrics = shaperFlags & QFontEngine::DesignMetrics;
+ if (!needsDesignMetrics && (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC
+ || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL
+ || renderMode == DWRITE_RENDERING_MODE_ALIASED)) {
hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize),
1.0f,
NULL,
- TRUE,
+ renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL,
glyphIndices.data(),
glyphIndices.size(),
glyphMetrics.data());
@@ -500,6 +516,53 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
}
}
+void QWindowsFontEngineDirectWrite::getUnscaledGlyph(glyph_t glyph,
+ QPainterPath *path,
+ glyph_metrics_t *metric)
+{
+ float advance = 0.0f;
+ UINT16 g = glyph;
+ DWRITE_GLYPH_OFFSET offset;
+ offset.advanceOffset = 0;
+ offset.ascenderOffset = 0;
+ GeometrySink geometrySink(path);
+ HRESULT hr = m_directWriteFontFace->GetGlyphRunOutline(m_unitsPerEm,
+ &g,
+ &advance,
+ &offset,
+ 1,
+ false,
+ false,
+ &geometrySink);
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__);
+ return;
+ }
+
+ DWRITE_GLYPH_METRICS glyphMetrics;
+ hr = m_directWriteFontFace->GetDesignGlyphMetrics(&g, 1, &glyphMetrics);
+ if (FAILED(hr)) {
+ qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__);
+ return;
+ }
+
+ QFixed advanceWidth = QFixed(int(glyphMetrics.advanceWidth));
+ QFixed leftSideBearing = QFixed(glyphMetrics.leftSideBearing);
+ QFixed rightSideBearing = QFixed(glyphMetrics.rightSideBearing);
+ QFixed advanceHeight = QFixed(int(glyphMetrics.advanceHeight));
+ QFixed verticalOriginY = QFixed(glyphMetrics.verticalOriginY);
+ QFixed topSideBearing = QFixed(glyphMetrics.topSideBearing);
+ QFixed bottomSideBearing = QFixed(glyphMetrics.bottomSideBearing);
+ QFixed width = advanceWidth - leftSideBearing - rightSideBearing;
+ QFixed height = advanceHeight - topSideBearing - bottomSideBearing;
+ *metric = glyph_metrics_t(leftSideBearing,
+ -verticalOriginY + topSideBearing,
+ width,
+ height,
+ advanceWidth,
+ 0);
+}
+
void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
QPainterPath *path, QTextItem::RenderFlags flags)
{
@@ -539,7 +602,9 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &g
for (int i = 0; i < glyphs.numGlyphs; ++i)
w += glyphs.effectiveAdvance(i);
- return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), ascent() + descent(), w, 0);
+ const QFixed leftBearing = firstLeftBearing(glyphs);
+ return glyph_metrics_t(leftBearing, -ascent(), w - leftBearing - lastRightBearing(glyphs),
+ ascent() + descent(), w, 0);
}
glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g)
@@ -618,7 +683,37 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph,
bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const
{
- return true;
+ DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef);
+ return (renderMode != DWRITE_RENDERING_MODE_GDI_CLASSIC
+ && renderMode != DWRITE_RENDERING_MODE_GDI_NATURAL
+ && renderMode != DWRITE_RENDERING_MODE_ALIASED);
+}
+
+QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const
+{
+ IDWriteFontFace2 *directWriteFontFace2;
+ if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2),
+ reinterpret_cast<void **>(&directWriteFontFace2)))) {
+ DWRITE_FONT_METRICS1 metrics;
+ directWriteFontFace2->GetMetrics(&metrics);
+
+ Properties p = QFontEngine::properties();
+ p.emSquare = metrics.designUnitsPerEm;
+ p.boundingBox = QRectF(metrics.glyphBoxLeft,
+ -metrics.glyphBoxTop,
+ metrics.glyphBoxRight - metrics.glyphBoxLeft,
+ metrics.glyphBoxTop - metrics.glyphBoxBottom);
+ p.ascent = metrics.ascent;
+ p.descent = metrics.descent;
+ p.leading = metrics.lineGap;
+ p.capHeight = metrics.capHeight;
+ p.lineWidth = metrics.underlineThickness;
+
+ directWriteFontFace2->Release();
+ return p;
+ } else {
+ return QFontEngine::properties();
+ }
}
QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
@@ -694,7 +789,10 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
if (SUCCEEDED(hr)) {
RECT rect;
- glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
+ glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED
+ ? DWRITE_TEXTURE_ALIASED_1x1
+ : DWRITE_TEXTURE_CLEARTYPE_3x1,
+ &rect);
if (rect.top == rect.bottom || rect.left == rect.right)
return QImage();
@@ -775,7 +873,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
b,
a,
colorGlyphsAnalysis,
- boundingRect);
+ boundingRect,
+ renderMode);
}
colorGlyphsAnalysis->Release();
@@ -802,7 +901,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
b,
a,
glyphAnalysis,
- boundingRect);
+ boundingRect,
+ renderMode);
}
glyphAnalysis->Release();
@@ -820,7 +920,8 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination,
float b,
float a,
IDWriteGlyphRunAnalysis *glyphAnalysis,
- const QRect &boundingRect)
+ const QRect &boundingRect,
+ DWRITE_RENDERING_MODE renderMode)
{
const int width = destination->width();
const int height = destination->height();
@@ -841,12 +942,14 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination,
BYTE *alphaValues = alphaValueArray.data();
memset(alphaValues, 0, size);
- HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1,
+ HRESULT hr = glyphAnalysis->CreateAlphaTexture(renderMode == DWRITE_RENDERING_MODE_ALIASED
+ ? DWRITE_TEXTURE_ALIASED_1x1
+ : DWRITE_TEXTURE_CLEARTYPE_3x1,
&rect,
alphaValues,
size);
if (SUCCEEDED(hr)) {
- if (destination->hasAlphaChannel()) {
+ if (destination->hasAlphaChannel()) { // Color glyphs
for (int y = 0; y < height; ++y) {
uint *dest = reinterpret_cast<uint *>(destination->scanLine(y));
BYTE *src = alphaValues + width * 3 * y;
@@ -864,7 +967,16 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination,
qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255));
}
}
+ } else if (renderMode == DWRITE_RENDERING_MODE_ALIASED) {
+ for (int y = 0; y < height; ++y) {
+ uint *dest = reinterpret_cast<uint *>(destination->scanLine(y));
+ BYTE *src = alphaValues + width * y;
+ for (int x = 0; x < width; ++x) {
+ int alpha = *(src++);
+ dest[x] = (alpha << 16) + (alpha << 8) + alpha;
+ }
+ }
} else {
for (int y = 0; y < height; ++y) {
uint *dest = reinterpret_cast<uint *>(destination->scanLine(y));
@@ -933,6 +1045,27 @@ void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request,
fontDef.pointSize = fontDef.pixelSize * 72. / dpi;
else if (fontDef.pixelSize == -1)
fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.);
+
+ m_faceId.variableAxes = request.variableAxisValues;
+
+#if QT_CONFIG(directwrite3)
+ IDWriteFontFace3 *face3 = nullptr;
+ if (SUCCEEDED(m_directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace3),
+ reinterpret_cast<void **>(&face3)))) {
+ IDWriteLocalizedStrings *names;
+ if (SUCCEEDED(face3->GetFaceNames(&names))) {
+ wchar_t englishLocale[] = L"en-us";
+ fontDef.styleName = QWindowsDirectWriteFontDatabase::localeString(names, englishLocale);
+ names->Release();
+ }
+
+ // Color font
+ if (face3->GetPaletteEntryCount() > 0)
+ glyphFormat = QFontEngine::Format_ARGB;
+
+ face3->Release();
+ }
+#endif
}
QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName)
@@ -1018,7 +1151,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
if (SUCCEEDED(hr)) {
RECT rect;
- glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
+ glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED ? DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1, &rect);
glyphAnalysis->Release();
int margin = glyphMargin(format);
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
index b672f8b2e8..d7c9a79267 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
@@ -22,6 +22,7 @@ QT_REQUIRE_CONFIG(directwrite);
#include <QtGui/private/qfontengine_p.h>
#include <QtCore/QSharedPointer>
+#include <dwrite.h>
struct IDWriteFont;
struct IDWriteFontFace;
@@ -52,8 +53,8 @@ public:
QFixed emSquareSize() const override;
glyph_t glyphIndex(uint ucs4) const override;
- bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
- ShaperFlags flags) const override;
+ int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
+ ShaperFlags flags) const override;
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override;
void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
@@ -98,6 +99,9 @@ public:
void initializeHeightMetrics() const override;
+ Properties properties() const override;
+ void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override;
+
private:
QImage imageForGlyph(glyph_t t,
const QFixedPoint &subPixelPosition,
@@ -105,8 +109,16 @@ private:
const QTransform &xform,
const QColor &color = QColor());
void collectMetrics();
- void renderGlyphRun(QImage *destination, float r, float g, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect);
+ void renderGlyphRun(QImage *destination,
+ float r,
+ float g,
+ float b,
+ float a,
+ IDWriteGlyphRunAnalysis *glyphAnalysis,
+ const QRect &boundingRect,
+ DWRITE_RENDERING_MODE renderMode);
static QString filenameFromFontFile(IDWriteFontFile *fontFile);
+ DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef) const;
const QSharedPointer<QWindowsFontEngineData> m_fontEngineData;