diff --git a/src/gui/configure.cmake b/src/gui/configure.cmake index 644b9268d8..21d98eab1f 100644 --- a/src/gui/configure.cmake +++ b/src/gui/configure.cmake @@ -580,7 +580,7 @@ qt_config_compile_test(directwrite3 int main(int, char **) { IUnknown *factory = nullptr; - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &factory); return 0; } diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp index b897e1f1db..499f43debb 100644 --- a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp @@ -106,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"; @@ -173,53 +179,38 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) IDWriteFontFace *face = nullptr; if (SUCCEEDED(font->CreateFontFace(&face))) { - QSupportedWritingSystems writingSystems; - - 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(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 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(); @@ -238,10 +229,144 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) } } +QSupportedWritingSystems QWindowsDirectWriteFontDatabase::supportedWritingSystems(IDWriteFontFace *face) const +{ + QSupportedWritingSystems writingSystems; + writingSystems.setSupported(QFontDatabase::Any); + + DirectWriteScope face1; + if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace1), + reinterpret_cast(&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(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 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 directWriteFontFace; + if (SUCCEEDED(data()->directWriteGdiInterop->CreateFontFaceFromHdc(dummy, &directWriteFontFace))) { + DirectWriteScope fontCollection; + if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) { + DirectWriteScope font; + if (SUCCEEDED(fontCollection->GetFontFromFontFace(*directWriteFontFace, &font))) { + + DirectWriteScope font1; + if (SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1), + reinterpret_cast(&font1)))) { + 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; + } + } + } + } + } + + 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(handle); - Q_ASSERT(face != nullptr); + const FontHandle *fontHandle = static_cast(handle); + IDWriteFontFace *face = fontHandle->fontFace; + if (face == nullptr || fontDef.styleStrategy & QFont::NoAntialias) { + 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) { @@ -327,7 +452,7 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray return QStringList(); } - QStringList ret; + QSet ret; for (int i = 0; i < faces.size(); ++i) { IDWriteFontFace *face = faces.at(i); wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH]; @@ -335,22 +460,18 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray wchar_t englishLocale[] = L"en-us"; 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; - QSupportedWritingSystems writingSystems; - writingSystems.setSupported(QFontDatabase::Any); - writingSystems.setSupported(QFontDatabase::Latin); - - IDWriteFontFace3 *face3 = nullptr; + QSupportedWritingSystems writingSystems = supportedWritingSystems(face); + DirectWriteScope face3; if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3), - reinterpret_cast(&face3)))) { + reinterpret_cast(&face3)))) { QString defaultLocaleFamilyName; QString englishLocaleFamilyName; - IDWriteLocalizedStrings *names; + IDWriteLocalizedStrings *names = nullptr; if (SUCCEEDED(face3->GetFamilyNames(&names))) { defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); englishLocaleFamilyName = localeString(names, englishLocale); @@ -367,6 +488,43 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray names->Release(); } + 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); + + 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); + + 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); + + names->Release(); + } + + 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); + + names->Release(); + } + QFont::Stretch stretch = fromDirectWriteStretch(face3->GetStretch()); QFont::Style style = fromDirectWriteStyle(face3->GetStyle()); QFont::Weight weight = fromDirectWriteWeight(face3->GetWeight()); @@ -389,12 +547,22 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray applicationFont->properties.append(properties); } - ret.append(englishLocaleFamilyName); - QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); + ret.insert(englishLocaleFamilyName); + QPlatformFontDatabase::registerFont(englishLocaleFamilyName, + englishLocaleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, englishLocaleFamilyName)); } - if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) { + if (!defaultLocaleFamilyName.isEmpty() && !ret.contains(defaultLocaleFamilyName)) { if (applicationFont != nullptr) { QFontDatabasePrivate::ApplicationFont::Properties properties; properties.style = style; @@ -404,12 +572,121 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray applicationFont->properties.append(properties); } - ret.append(defaultLocaleFamilyName); - QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); + ret.insert(defaultLocaleFamilyName); + QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, + defaultLocaleStyleName, + QString(), + weight, + style, + stretch, + antialias, + scalable, + size, + fixed, + writingSystems, + new FontHandle(face, defaultLocaleFamilyName)); + } + + 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); + } + + 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)); } - face3->Release(); } else { qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face."; } @@ -417,18 +694,7 @@ QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray face->Release(); } - return ret; -} - -void QWindowsDirectWriteFontDatabase::releaseHandle(void *handle) -{ - IDWriteFontFace *face = reinterpret_cast(handle); - face->Release(); -} - -bool QWindowsDirectWriteFontDatabase::fontsAlwaysScalable() const -{ - return true; + return ret.values(); } bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family) const @@ -437,6 +703,29 @@ 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(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(lparam); + if (!db->hasPopulatedFont(faceName)) { + db->registerFontFamily(faceName); + db->registerBitmapFont(faceName); + } + } + } + return 1; // continue +} + void QWindowsDirectWriteFontDatabase::populateFontDatabase() { wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH]; @@ -446,10 +735,19 @@ void QWindowsDirectWriteFontDatabase::populateFontDatabase() const QString defaultFontName = defaultFont().families().constFirst(); const QString systemDefaultFontName = systemDefaultFont().families().constFirst(); - IDWriteFontCollection *fontCollection; - if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) { + DirectWriteScope fontCollection; + DirectWriteScope factory6; + if (FAILED(data()->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory6), + reinterpret_cast(&factory6)))) { + qCWarning(lcQpaFonts) << "Can't initialize IDWriteFactory6. Use GDI font engine instead."; + return; + } + + if (SUCCEEDED(factory6->GetSystemFontCollection(false, + DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC, + &fontCollection))) { for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) { - IDWriteFontFamily *fontFamily; + IDWriteFontFamily2 *fontFamily; if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) { QString defaultLocaleName; QString englishLocaleName; @@ -493,6 +791,17 @@ void QWindowsDirectWriteFontDatabase::populateFontDatabase() } } } + + // 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(this), 0); + ReleaseDC(0, dummy); + } } QFont QWindowsDirectWriteFontDatabase::defaultFont() const diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h index 41a1640c16..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 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,21 +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 m_populatedFonts; + QSet m_populatedBitmapFonts; }; QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp index 51254f7727..0d84475049 100644 --- a/src/gui/text/windows/qwindowsfontdatabase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabase.cpp @@ -434,18 +434,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(faceNamePtr), faceName.data(), sizeof(wchar_t) * nameLength); - faceNamePtr[nameLength] = u'\0'; - } - return faceNamePtr; -} - namespace { struct StoreFontPayload { StoreFontPayload(const QString &family, @@ -554,19 +542,19 @@ static bool addFontToDatabase(QString 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 @@ -580,7 +568,7 @@ static bool addFontToDatabase(QString 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) @@ -752,7 +740,8 @@ QWindowsFontDatabase::~QWindowsFontDatabase() QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { - const QString faceName(static_cast(handle)); + FontHandle *fontHandle = static_cast(handle); + const QString faceName = fontHandle->faceName.left(LF_FACESIZE - 1); QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName, defaultVerticalDPI(), data()); @@ -1124,10 +1113,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(handle); - delete[] faceName; + delete static_cast(handle); } QString QWindowsFontDatabase::fontDir() const diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h index dfaa1f9c0e..0c99c91fde 100644 --- a/src/gui/text/windows/qwindowsfontdatabase_p.h +++ b/src/gui/text/windows/qwindowsfontdatabase_p.h @@ -75,9 +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 addDefaultEUDCFont(); struct WinApplicationFont { diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index cef739201b..84e619b0d9 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -565,16 +565,27 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory IUnknown *result = nullptr; # if QT_CONFIG(directwrite3) - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result); - - if (result == nullptr) - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); -# endif - - if (result == nullptr) - DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &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) { + 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; diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index e5a2c7a2b8..6043406c4d 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -365,6 +365,8 @@ void QWindowsFontEngineDirectWrite::collectMetrics() quint16 advanceWidthMax = qFromBigEndian(table.constData() + advanceWidthMaxLocation); m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax); } + + loadKerningPairs(emSquareSize() / QFixed::fromReal(fontDef.pixelSize)); } QFixed QWindowsFontEngineDirectWrite::underlinePosition() const @@ -672,7 +674,8 @@ 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); } QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index 3995f64e07..0f517a40d8 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -423,8 +423,10 @@ void tst_QFontDatabase::condensedFontMatching() QFont f; f.setStyleStrategy(QFont::NoFontMerging); QFontPrivate *font_d = QFontPrivate::get(f); - if (font_d->engineForScript(QChar::Script_Common)->type() != QFontEngine::Freetype) + if (font_d->engineForScript(QChar::Script_Common)->type() != QFontEngine::Freetype + && font_d->engineForScript(QChar::Script_Common)->type() != QFontEngine::DirectWrite) { QEXPECT_FAIL("","No matching of sub-family by stretch on Windows", Continue); + } #endif QCOMPARE(QFontMetrics(tfcByStretch).horizontalAdvance(testString()),