diff options
Diffstat (limited to 'src/gui/text/windows/qwindowsfontdatabasebase.cpp')
-rw-r--r-- | src/gui/text/windows/qwindowsfontdatabasebase.cpp | 346 |
1 files changed, 196 insertions, 150 deletions
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp index 6b6558792f..84e619b0d9 100644 --- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -1,46 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qwindowsfontdatabasebase_p.h" #include "qwindowsfontdatabase_p.h" -#include <QtCore/private/qsystemlibrary_p.h> #include <QtCore/QThreadStorage> #include <QtCore/QtEndian> @@ -56,6 +19,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + // Helper classes for creating font engines directly from font data namespace { @@ -275,14 +240,11 @@ QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(const QString & // nameRecord now points to string data quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord); - const quint16 *sourceString = newFamilyName.utf16(); - for (int i = 0; i < newFamilyName.size(); ++i) - stringStorage[i] = qbswap<quint16>(sourceString[i]); - stringStorage += newFamilyName.size(); + for (QChar ch : newFamilyName) + *stringStorage++ = qbswap<quint16>(quint16(ch.unicode())); - sourceString = regularString.utf16(); - for (int i = 0; i < regularString.size(); ++i) - stringStorage[i] = qbswap<quint16>(sourceString[i]); + for (QChar ch : regularString) + *stringStorage++ = qbswap<quint16>(quint16(ch.unicode())); } quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data()); @@ -397,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) @@ -416,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; @@ -473,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 @@ -582,36 +559,34 @@ bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d) } #if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) -// ### Qt 6: Link directly to dwrite instead -typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **); -static inline DWriteCreateFactoryType resolveDWriteCreateFactory() -{ - QSystemLibrary library(QStringLiteral("dwrite")); - QFunctionPointer result = library.resolve("DWriteCreateFactory"); - if (Q_UNLIKELY(!result)) { - qWarning("Unable to load dwrite.dll"); - return nullptr; - } - return reinterpret_cast<DWriteCreateFactoryType>(result); -} - void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory) { *factory = nullptr; - - static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory(); - if (!dWriteCreateFactory) - return; - 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) - dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); if (result == nullptr) { - if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { + 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; } @@ -621,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) @@ -713,16 +681,6 @@ LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, cons fam.truncate(LF_FACESIZE - 1); } - if (fam.isEmpty()) - fam = QStringLiteral("MS Sans Serif"); - - if (fam == QLatin1String("MS Sans Serif") - && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) { - fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale - } - if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap)) - fam = QStringLiteral("Courier New"); - memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t)); return lf; @@ -755,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; @@ -794,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; @@ -825,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); @@ -867,7 +894,7 @@ QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint) default: break; } - return QStringLiteral("MS Shell Dlg 2"); + return QStringLiteral("Tahoma"); } // Creation functions @@ -964,4 +991,23 @@ QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &fami return result; } +QFontDef QWindowsFontDatabaseBase::sanitizeRequest(QFontDef request) const +{ + QFontDef req = request; + const QString fam = request.families.front(); + if (fam.isEmpty()) + req.families[0] = QStringLiteral("MS Sans Serif"); + + if (fam == "MS Sans Serif"_L1) { + int height = -qRound(request.pixelSize); + // MS Sans Serif has bearing problems in italic, and does not scale + if (request.style == QFont::StyleItalic || (height > 18 && height != 24)) + req.families[0] = QStringLiteral("Arial"); + } + + if (!(request.styleStrategy & QFont::StyleStrategy::PreferBitmap) && fam == u"Courier") + req.families[0] = QStringLiteral("Courier New"); + return req; +} + QT_END_NAMESPACE |