From b3e0732740d8fdace82d91973dac87261402604f Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 28 May 2020 08:20:55 +0200 Subject: Move windows font databases into QtGui Requires adapting a few config checks since cmake currently does not detect directwrite. Task-number: QTBUG-83255 Task-number: QTBUG-83931 Change-Id: I521f1924f701260b41dccbcecf87b19f08df5ccc Reviewed-by: Alexandru Croitor --- src/gui/.prev_CMakeLists.txt | 61 +- src/gui/CMakeLists.txt | 61 +- src/gui/text/text.pri | 5 + .../windows/qwindowsdirectwritefontdatabase.cpp | 478 ++++++++ .../windows/qwindowsdirectwritefontdatabase_p.h | 96 ++ src/gui/text/windows/qwindowsfontdatabase.cpp | 1235 ++++++++++++++++++++ src/gui/text/windows/qwindowsfontdatabase_ft.cpp | 444 +++++++ src/gui/text/windows/qwindowsfontdatabase_ft_p.h | 79 ++ src/gui/text/windows/qwindowsfontdatabase_p.h | 180 +++ src/gui/text/windows/qwindowsfontdatabasebase.cpp | 971 +++++++++++++++ src/gui/text/windows/qwindowsfontdatabasebase_p.h | 138 +++ src/gui/text/windows/qwindowsfontengine.cpp | 1204 +++++++++++++++++++ src/gui/text/windows/qwindowsfontengine_p.h | 175 +++ .../text/windows/qwindowsfontenginedirectwrite.cpp | 1030 ++++++++++++++++ .../text/windows/qwindowsfontenginedirectwrite_p.h | 152 +++ src/gui/text/windows/qwindowsnativeimage.cpp | 158 +++ src/gui/text/windows/qwindowsnativeimage_p.h | 89 ++ src/gui/text/windows/windows.pri | 41 + .../fontdatabases/.prev_CMakeLists.txt | 61 - src/platformsupport/fontdatabases/CMakeLists.txt | 61 - .../fontdatabases/fontdatabases.pro | 4 - .../windows/qwindowsdirectwritefontdatabase.cpp | 478 -------- .../windows/qwindowsdirectwritefontdatabase_p.h | 96 -- .../fontdatabases/windows/qwindowsfontdatabase.cpp | 1231 ------------------- .../windows/qwindowsfontdatabase_ft.cpp | 444 ------- .../windows/qwindowsfontdatabase_ft_p.h | 79 -- .../fontdatabases/windows/qwindowsfontdatabase_p.h | 174 --- .../windows/qwindowsfontdatabasebase.cpp | 985 ---------------- .../windows/qwindowsfontdatabasebase_p.h | 138 --- .../fontdatabases/windows/qwindowsfontengine.cpp | 1204 ------------------- .../fontdatabases/windows/qwindowsfontengine_p.h | 175 --- .../windows/qwindowsfontenginedirectwrite.cpp | 1030 ---------------- .../windows/qwindowsfontenginedirectwrite_p.h | 152 --- .../fontdatabases/windows/qwindowsnativeimage.cpp | 158 --- .../fontdatabases/windows/qwindowsnativeimage_p.h | 89 -- .../fontdatabases/windows/windows.pri | 43 - src/plugins/platforms/direct2d/direct2d.pro | 3 +- .../direct2d/qwindowsdirect2dpaintengine.cpp | 3 +- src/plugins/platforms/minimal/.prev_CMakeLists.txt | 2 +- src/plugins/platforms/minimal/CMakeLists.txt | 2 +- src/plugins/platforms/minimal/minimal.pro | 2 +- .../platforms/minimal/qminimalintegration.cpp | 4 +- .../platforms/offscreen/.prev_CMakeLists.txt | 2 +- src/plugins/platforms/offscreen/CMakeLists.txt | 2 +- src/plugins/platforms/offscreen/offscreen.pro | 2 +- src/plugins/platforms/windows/.prev_CMakeLists.txt | 1 - src/plugins/platforms/windows/CMakeLists.txt | 1 - .../platforms/windows/qwindowsbackingstore.cpp | 2 +- .../platforms/windows/qwindowsintegration.cpp | 5 +- .../platforms/windows/qwindowsintegration.h | 2 +- .../platforms/windows/qwindowsnativeinterface.cpp | 2 +- src/plugins/platforms/windows/qwindowstheme.cpp | 19 +- src/plugins/platforms/windows/windows.pro | 3 +- 53 files changed, 6620 insertions(+), 6636 deletions(-) create mode 100644 src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp create mode 100644 src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h create mode 100644 src/gui/text/windows/qwindowsfontdatabase.cpp create mode 100644 src/gui/text/windows/qwindowsfontdatabase_ft.cpp create mode 100644 src/gui/text/windows/qwindowsfontdatabase_ft_p.h create mode 100644 src/gui/text/windows/qwindowsfontdatabase_p.h create mode 100644 src/gui/text/windows/qwindowsfontdatabasebase.cpp create mode 100644 src/gui/text/windows/qwindowsfontdatabasebase_p.h create mode 100644 src/gui/text/windows/qwindowsfontengine.cpp create mode 100644 src/gui/text/windows/qwindowsfontengine_p.h create mode 100644 src/gui/text/windows/qwindowsfontenginedirectwrite.cpp create mode 100644 src/gui/text/windows/qwindowsfontenginedirectwrite_p.h create mode 100644 src/gui/text/windows/qwindowsnativeimage.cpp create mode 100644 src/gui/text/windows/qwindowsnativeimage_p.h create mode 100644 src/gui/text/windows/windows.pri delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp delete mode 100644 src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h delete mode 100644 src/platformsupport/fontdatabases/windows/windows.pri diff --git a/src/gui/.prev_CMakeLists.txt b/src/gui/.prev_CMakeLists.txt index e53ec30af8..dba7b9d3cb 100644 --- a/src/gui/.prev_CMakeLists.txt +++ b/src/gui/.prev_CMakeLists.txt @@ -306,6 +306,15 @@ qt_extend_target(Gui CONDITION WIN32 platform/windows/qwindowsguieventdispatcher.cpp platform/windows/qwindowsguieventdispatcher_p.h rhi/qrhid3d11.cpp rhi/qrhid3d11_p.h rhi/qrhid3d11_p_p.h + text/windows/qwindowsfontdatabase.cpp text/windows/qwindowsfontdatabase_p.h + text/windows/qwindowsfontdatabasebase.cpp text/windows/qwindowsfontdatabasebase_p.h + text/windows/qwindowsfontengine.cpp text/windows/qwindowsfontengine_p.h + text/windows/qwindowsnativeimage.cpp text/windows/qwindowsnativeimage_p.h + LIBRARIES + advapi32 + gdi32 + ole32 + user32 PUBLIC_LIBRARIES d3d11 dxgi @@ -551,6 +560,52 @@ qt_extend_target(Gui CONDITION APPLE AND QT_FEATURE_freetype WrapFreetype::WrapFreetype ) +qt_extend_target(Gui CONDITION QT_FEATURE_freetype AND WIN32 + SOURCES + text/windows/qwindowsfontdatabase_ft.cpp text/windows/qwindowsfontdatabase_ft_p.h + LIBRARIES + WrapFreetype::WrapFreetype +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 + SOURCES + text/windows/qwindowsfontenginedirectwrite.cpp text/windows/qwindowsfontenginedirectwrite_p.h + LIBRARIES + d2d1 +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite3 AND WIN32 + SOURCES + text/windows/qwindowsdirectwritefontdatabase.cpp text/windows/qwindowsdirectwritefontdatabase_p.h + DEFINES + QT_USE_DIRECTWRITE2 + QT_USE_DIRECTWRITE3 + LIBRARIES + dwrite_3 +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite2 AND WIN32 AND NOT QT_FEATURE_directwrite3 + DEFINES + QT_USE_DIRECTWRITE2 + LIBRARIES + dwrite_2 +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 AND NOT QT_FEATURE_directwrite2 AND NOT QT_FEATURE_directwrite3 + LIBRARIES + dwrite +) + +qt_extend_target(Gui CONDITION WIN32 AND (NOT QT_FEATURE_direct2d OR NOT QT_FEATURE_directwrite) + DEFINES + QT_NO_DIRECTWRITE +) + +qt_extend_target(Gui CONDITION MINGW AND WIN32 + LIBRARIES + uuid +) + qt_extend_target(Gui CONDITION UNIX AND NOT ANDROID AND NOT INTEGRITY AND NOT (TEST_architecture_arch STREQUAL "arm64") AND NOT UIKIT DEFINES ENABLE_PIXMAN_DRAWHELPERS @@ -616,7 +671,7 @@ qt_extend_target(Gui CONDITION QT_FEATURE_vulkan Vulkan::Vulkan_nolink ) -#### Keys ignored in scope 89:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vkgen: +#### Keys ignored in scope 99:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vkgen: # QMAKE_EXTRA_COMPILERS = "qvkgen_h" "qvkgen_ph" "qvkgen_pimpl" # QMAKE_QVKGEN_INPUT = "vulkan/vk.xml" # QMAKE_QVKGEN_LICENSE_HEADER = "$$QT_SOURCE_TREE/header.LGPL" @@ -632,10 +687,10 @@ qt_extend_target(Gui CONDITION QT_FEATURE_vulkan # qvkgen_pimpl.input = "QMAKE_QVKGEN_INPUT" # qvkgen_pimpl.output = "$$OUT_PWD/vulkan/qvulkanfunctions_p.cpp" -#### Keys ignored in scope 90:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan: +#### Keys ignored in scope 100:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan: # qvkgen_h.variable_out = "HEADERS" -#### Keys ignored in scope 91:.:vulkan:vulkan/vulkan.pri:else: +#### Keys ignored in scope 101:.:vulkan:vulkan/vulkan.pri:else: # qvkgen_h.CONFIG = "target_predeps" "no_link" qt_extend_target(Gui CONDITION WASM diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 940b81e264..c38129c028 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -395,6 +395,15 @@ qt_extend_target(Gui CONDITION WIN32 platform/windows/qwindowsguieventdispatcher.cpp platform/windows/qwindowsguieventdispatcher_p.h rhi/qrhid3d11.cpp rhi/qrhid3d11_p.h rhi/qrhid3d11_p_p.h + text/windows/qwindowsfontdatabase.cpp text/windows/qwindowsfontdatabase_p.h + text/windows/qwindowsfontdatabasebase.cpp text/windows/qwindowsfontdatabasebase_p.h + text/windows/qwindowsfontengine.cpp text/windows/qwindowsfontengine_p.h + text/windows/qwindowsnativeimage.cpp text/windows/qwindowsnativeimage_p.h + LIBRARIES + advapi32 + gdi32 + ole32 + user32 PUBLIC_LIBRARIES d3d11 dxgi @@ -659,6 +668,52 @@ qt_extend_target(Gui CONDITION APPLE AND QT_FEATURE_freetype WrapFreetype::WrapFreetype ) +qt_extend_target(Gui CONDITION QT_FEATURE_freetype AND WIN32 + SOURCES + text/windows/qwindowsfontdatabase_ft.cpp text/windows/qwindowsfontdatabase_ft_p.h + LIBRARIES + WrapFreetype::WrapFreetype +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 + SOURCES + text/windows/qwindowsfontenginedirectwrite.cpp text/windows/qwindowsfontenginedirectwrite_p.h + LIBRARIES + d2d1 +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite3 AND WIN32 + SOURCES + text/windows/qwindowsdirectwritefontdatabase.cpp text/windows/qwindowsdirectwritefontdatabase_p.h + DEFINES + QT_USE_DIRECTWRITE2 + QT_USE_DIRECTWRITE3 + LIBRARIES + dwrite_3 +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite2 AND WIN32 AND NOT QT_FEATURE_directwrite3 + DEFINES + QT_USE_DIRECTWRITE2 + LIBRARIES + dwrite_2 +) + +qt_extend_target(Gui CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 AND NOT QT_FEATURE_directwrite2 AND NOT QT_FEATURE_directwrite3 + LIBRARIES + dwrite +) + +qt_extend_target(Gui CONDITION WIN32 AND (NOT QT_FEATURE_direct2d OR NOT QT_FEATURE_directwrite) + DEFINES + QT_NO_DIRECTWRITE +) + +qt_extend_target(Gui CONDITION MINGW AND WIN32 + LIBRARIES + uuid +) + qt_extend_target(Gui CONDITION UNIX AND NOT ANDROID AND NOT INTEGRITY AND NOT (TEST_architecture_arch STREQUAL "arm64") AND NOT UIKIT DEFINES ENABLE_PIXMAN_DRAWHELPERS @@ -724,7 +779,7 @@ qt_extend_target(Gui CONDITION QT_FEATURE_vulkan Vulkan::Vulkan_nolink ) -#### Keys ignored in scope 89:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vkgen: +#### Keys ignored in scope 99:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vkgen: # special case begin # We must always generate syncqt-injected header files, # because we added a custom command earlier for those for framework builds. @@ -780,10 +835,10 @@ add_custom_command( # qvkgen_pimpl.input = "QMAKE_QVKGEN_INPUT" # qvkgen_pimpl.output = "$$OUT_PWD/vulkan/qvulkanfunctions_p.cpp" -#### Keys ignored in scope 90:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan: +#### Keys ignored in scope 100:.:vulkan:vulkan/vulkan.pri:QT_FEATURE_vulkan: # qvkgen_h.variable_out = "HEADERS" -#### Keys ignored in scope 91:.:vulkan:vulkan/vulkan.pri:else: +#### Keys ignored in scope 101:.:vulkan:vulkan/vulkan.pri:else: # qvkgen_h.CONFIG = "target_predeps" "no_link" qt_extend_target(Gui CONDITION WASM diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 192cd5f426..8c36dce6b6 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -131,3 +131,8 @@ qtConfig(freetype) { darwin { include($$PWD/coretext/coretext.pri) } + +win32 { + include($$PWD/windows/windows.pri) +} + diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp new file mode 100644 index 0000000000..d2fb909dea --- /dev/null +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase.cpp @@ -0,0 +1,478 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qwindowsdirectwritefontdatabase_p.h" +#include "qwindowsfontenginedirectwrite_p.h" +#include "qwindowsfontdatabase_p.h" + +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +#ifdef QT_USE_DIRECTWRITE3 + +// Defined in gui/text/qfontdatabase.cpp +Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script); + +QWindowsDirectWriteFontDatabase::QWindowsDirectWriteFontDatabase() +{ + qCDebug(lcQpaFonts) << "Creating DirectWrite database"; +} + +QWindowsDirectWriteFontDatabase::~QWindowsDirectWriteFontDatabase() +{ + for (auto it = m_populatedFonts.begin(); it != m_populatedFonts.end(); ++it) + it.value()->Release(); +} + +QString QWindowsDirectWriteFontDatabase::localeString(IDWriteLocalizedStrings *names, + wchar_t localeName[]) +{ + uint index; + BOOL exists; + if (SUCCEEDED(names->FindLocaleName(localeName, &index, &exists)) && exists) { + uint length; + if (SUCCEEDED(names->GetStringLength(index, &length)) && length > 0) { + QVarLengthArray buffer(int(length) + 1); + if (SUCCEEDED(names->GetString(index, buffer.data(), length + 1))) + return QString::fromWCharArray(buffer.data()); + } + } + + return QString(); +} + +static QFont::Stretch fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch) +{ + switch (stretch) { + case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return QFont::UltraCondensed; + case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return QFont::ExtraCondensed; + case DWRITE_FONT_STRETCH_CONDENSED: return QFont::Condensed; + case DWRITE_FONT_STRETCH_SEMI_CONDENSED: return QFont::SemiCondensed; + case DWRITE_FONT_STRETCH_NORMAL: return QFont::Unstretched; + case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return QFont::SemiExpanded; + case DWRITE_FONT_STRETCH_EXPANDED: return QFont::Expanded; + case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return QFont::ExtraExpanded; + case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return QFont::UltraExpanded; + default: return QFont::AnyStretch; + } +} + +static QFont::Weight fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight) +{ + return QPlatformFontDatabase::weightFromInteger(int(weight)); +} + +static DWRITE_FONT_STYLE toDirectWriteStyle(QFont::Style style) +{ + switch (style) { + case QFont::StyleNormal: return DWRITE_FONT_STYLE_NORMAL; + case QFont::StyleOblique: return DWRITE_FONT_STYLE_OBLIQUE; + case QFont::StyleItalic: return DWRITE_FONT_STYLE_ITALIC; + default: return DWRITE_FONT_STYLE_NORMAL; + } +} + +static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style) +{ + switch (style) { + case DWRITE_FONT_STYLE_NORMAL: return QFont::StyleNormal; + case DWRITE_FONT_STYLE_OBLIQUE: return QFont::StyleOblique; + case DWRITE_FONT_STYLE_ITALIC: return QFont::StyleItalic; + default: return QFont::StyleNormal; + } +} + +void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) +{ + auto it = m_populatedFonts.find(familyName); + IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr; + if (fontFamily == nullptr) { + qCWarning(lcQpaFonts) << "Cannot find" << familyName << "in list of fonts"; + return; + } + + qCDebug(lcQpaFonts) << "Populate family:" << familyName; + + 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 QString foundryName; // No such concept. + const bool scalable = true; + const bool antialias = false; + const int size = SMOOTH_SCALABLE; + + IDWriteFontList *matchingFonts; + if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR, + DWRITE_FONT_STRETCH_NORMAL, + DWRITE_FONT_STYLE_NORMAL, + &matchingFonts))) { + for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) { + IDWriteFont *font; + if (SUCCEEDED(matchingFonts->GetFont(j, &font))) { + IDWriteFont1 *font1 = nullptr; + if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1), + reinterpret_cast(&font1)))) { + qCWarning(lcQpaFonts) << "COM object does not support IDWriteFont1"; + continue; + } + + QString defaultLocaleFamilyName; + QString englishLocaleFamilyName; + + IDWriteFontFamily *fontFamily2; + if (SUCCEEDED(font1->GetFontFamily(&fontFamily2))) { + IDWriteLocalizedStrings *names; + if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) { + defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleFamilyName = localeString(names, englishLocale); + + names->Release(); + } + + fontFamily2->Release(); + } + + if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty()) + englishLocaleFamilyName = familyName; + + { + IDWriteLocalizedStrings *names; + if (SUCCEEDED(font1->GetFaceNames(&names))) { + QString defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + 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(); + + qCDebug(lcQpaFonts) << "Family" << familyName << "has english variant" << englishLocaleStyleName << ", in default locale:" << defaultLocaleStyleName << stretch << style << weight << fixed; + + 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(qbswap(MAKE_TAG('O','S','/','2')), + &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; + } + } + } + + 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(); + } + + if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) { + QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); + face->AddRef(); + } + + face->Release(); + } + + names->Release(); + } + } + + font1->Release(); + font->Release(); + } + } + + matchingFonts->Release(); + } +} + +QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) +{ + IDWriteFontFace *face = reinterpret_cast(handle); + Q_ASSERT(face != nullptr); + + QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(face, fontDef.pixelSize, data()); + fontEngine->initFontInfo(fontDef, defaultVerticalDPI()); + + return fontEngine; +} + +QStringList QWindowsDirectWriteFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const +{ + QStringList result; + result.append(familyForStyleHint(styleHint)); + result.append(extraTryFontsForFamily(family)); + result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); + + qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint + << script << result; + return result; +} + +QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont) +{ + qCDebug(lcQpaFonts) << "Adding application font" << fileName; + + QByteArray loadedData = fontData; + if (loadedData.isEmpty()) { + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + qCWarning(lcQpaFonts) << "Cannot open" << fileName << "for reading."; + return QStringList(); + } + loadedData = file.readAll(); + } + + IDWriteFontFace *face = createDirectWriteFace(loadedData); + if (face == nullptr) { + 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"; + + 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); + + QStringList ret; + IDWriteFontFace3 *face3 = nullptr; + if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3), + reinterpret_cast(&face3)))) { + QString defaultLocaleFamilyName; + QString englishLocaleFamilyName; + + IDWriteLocalizedStrings *names; + if (SUCCEEDED(face3->GetFamilyNames(&names))) { + defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleFamilyName = localeString(names, englishLocale); + + names->Release(); + } + + QString defaultLocaleStyleName; + QString englishLocaleStyleName; + if (SUCCEEDED(face3->GetFaceNames(&names))) { + defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); + englishLocaleStyleName = localeString(names, englishLocale); + + names->Release(); + } + + 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); + } + + ret.append(englishLocaleFamilyName); + QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); + face->AddRef(); + } + + 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); + } + + ret.append(defaultLocaleFamilyName); + QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); + face->AddRef(); + } + + face3->Release(); + } else { + qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face."; + } + + face->Release(); + + return ret; +} + +void QWindowsDirectWriteFontDatabase::releaseHandle(void *handle) +{ + IDWriteFontFace *face = reinterpret_cast(handle); + face->Release(); +} + +bool QWindowsDirectWriteFontDatabase::fontsAlwaysScalable() const +{ + return true; +} + +bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family) const +{ + Q_UNUSED(family); + return false; +} + +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"; + + QString defaultFontName = defaultFont().family(); + QString systemDefaultFontName = systemDefaultFont().family(); + + IDWriteFontCollection *fontCollection; + if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) { + for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) { + IDWriteFontFamily *fontFamily; + if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) { + QString defaultLocaleName; + QString englishLocaleName; + + IDWriteLocalizedStrings *names; + if (SUCCEEDED(fontFamily->GetFamilyNames(&names))) { + if (hasDefaultLocale) + defaultLocaleName = localeString(names, defaultLocale); + + 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); + fontFamily->AddRef(); + + if (defaultLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) { + qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << defaultLocaleName; + + m_populatedFonts.insert(systemDefaultFontName, fontFamily); + fontFamily->AddRef(); + } + } + + if (!englishLocaleName.isEmpty() && englishLocaleName != defaultLocaleName) { + registerFontFamily(englishLocaleName); + 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); + fontFamily->AddRef(); + } + } + + fontFamily->Release(); + } + } + } +} + +QFont QWindowsDirectWriteFontDatabase::defaultFont() const +{ + return QFont(QStringLiteral("Segoe UI")); +} + +#endif // QT_USE_DIRECTWRITE3 + +QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h new file mode 100644 index 0000000000..5637b5dfb0 --- /dev/null +++ b/src/gui/text/windows/qwindowsdirectwritefontdatabase_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSDIRECTWRITEFONTDATABASE_P_H +#define QWINDOWSDIRECTWRITEFONTDATABASE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qwindowsfontdatabasebase_p.h" + +#include +#include + +struct IDWriteFactory; +struct IDWriteFont; +struct IDWriteFontFamily; +struct IDWriteLocalizedStrings; + +QT_BEGIN_NAMESPACE + +#ifdef QT_USE_DIRECTWRITE3 + +class Q_GUI_EXPORT QWindowsDirectWriteFontDatabase : public QWindowsFontDatabaseBase +{ + Q_DISABLE_COPY_MOVE(QWindowsDirectWriteFontDatabase) +public: + QWindowsDirectWriteFontDatabase(); + ~QWindowsDirectWriteFontDatabase() override; + + void populateFontDatabase() override; + void populateFamily(const QString &familyName) override; + QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) 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; + +private: + static QString localeString(IDWriteLocalizedStrings *names, wchar_t localeName[]); + + QHash m_populatedFonts; +}; + +#endif // QT_USE_DIRECTWRITE3 + +QT_END_NAMESPACE + +#endif // QWINDOWSDIRECTWRITEFONTDATABASE_P_H diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp new file mode 100644 index 0000000000..7af20df94c --- /dev/null +++ b/src/gui/text/windows/qwindowsfontdatabase.cpp @@ -0,0 +1,1235 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#include "qwindowsfontdatabase_p.h" +#include "qwindowsfontdatabase_ft_p.h" // for default font +#include "qwindowsfontengine_p.h" +#include "qwindowsfontenginedirectwrite_p.h" +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#if !defined(QT_NO_DIRECTWRITE) +# if defined(QT_USE_DIRECTWRITE2) +# include +# else +# include +# endif +# include +# include "qwindowsdirectwritefontdatabase_p.h" +#endif + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") + +#ifndef QT_NO_DIRECTWRITE +// ### fixme: Consider direct linking of dwrite.dll once Windows Vista pre SP2 is dropped (QTBUG-49711) + +typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **); + +static inline bool useDirectWrite(QFont::HintingPreference hintingPreference, + const QString &familyName = QString(), + bool isColorFont = false) +{ + const unsigned options = QWindowsFontDatabase::fontOptions(); + if (Q_UNLIKELY(options & QWindowsFontDatabase::DontUseDirectWriteFonts)) + return false; + + // At some scales, GDI will misrender the MingLiU font, so we force use of + // DirectWrite to work around the issue. + if (Q_UNLIKELY(familyName.startsWith(QLatin1String("MingLiU")))) + return true; + + if (isColorFont) + return (options & QWindowsFontDatabase::DontUseColorFonts) == 0; + + return hintingPreference == QFont::PreferNoHinting + || hintingPreference == QFont::PreferVerticalHinting + || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting); +} +#endif // !QT_NO_DIRECTWRITE + +/*! + \struct QWindowsFontEngineData + \brief Static constant data shared by the font engines. +*/ + +QWindowsFontEngineData::QWindowsFontEngineData() + : fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma()) +{ + // from qapplication_win.cpp + UINT result = 0; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0)) + clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE); + + const qreal gray_gamma = 2.31; + for (int i=0; i<256; ++i) + pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); + + HDC displayDC = GetDC(0); + hdc = CreateCompatibleDC(displayDC); + ReleaseDC(0, displayDC); +} + +unsigned QWindowsFontDatabase::m_fontOptions = 0; + +void QWindowsFontDatabase::setFontOptions(unsigned options) +{ + m_fontOptions = options & (QWindowsFontDatabase::DontUseDirectWriteFonts | + QWindowsFontDatabase::DontUseColorFonts); +} + +unsigned QWindowsFontDatabase::fontOptions() +{ + return m_fontOptions; +} + +qreal QWindowsFontDatabase::fontSmoothingGamma() +{ + int winSmooth; + qreal result = 1; + if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) + result = qreal(winSmooth) / qreal(1000.0); + + // Safeguard ourselves against corrupt registry values... + if (result > 5 || result < 1) + result = qreal(1.4); + return result; +} + +/*! + \class QWindowsFontDatabase + \brief Font database for Windows + + \note The Qt 4.8 WIndows font database employed a mechanism of + delayed population of the database again passing a font name + to EnumFontFamiliesEx(), working around the fact that + EnumFontFamiliesEx() does not list all fonts by default. + This should be introduced to QPA as well? + + \internal +*/ + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const QFontDef &def) +{ + QDebugStateSaver saver(d); + d.nospace(); + d.noquote(); + d << "QFontDef(Family=\"" << def.family << '"'; + if (!def.styleName.isEmpty()) + d << ", stylename=" << def.styleName; + d << ", pointsize=" << def.pointSize << ", pixelsize=" << def.pixelSize + << ", styleHint=" << def.styleHint << ", weight=" << def.weight + << ", stretch=" << def.stretch << ", hintingPreference=" + << def.hintingPreference << ')'; + return d; +} + +void QWindowsFontDatabase::debugFormat(QDebug &d, const LOGFONT &lf) +{ + d << "LOGFONT(\"" << QString::fromWCharArray(lf.lfFaceName) + << "\", lfWidth=" << lf.lfWidth << ", lfHeight=" << lf.lfHeight << ')'; +} + +QDebug operator<<(QDebug d, const LOGFONT &lf) +{ + QDebugStateSaver saver(d); + d.nospace(); + d.noquote(); + QWindowsFontDatabase::debugFormat(d, lf); + return d; +} +#endif // !QT_NO_DEBUG_STREAM + +static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) +{ + switch (charSet) { + case ANSI_CHARSET: + case EASTEUROPE_CHARSET: + case BALTIC_CHARSET: + case TURKISH_CHARSET: + return QFontDatabase::Latin; + case GREEK_CHARSET: + return QFontDatabase::Greek; + case RUSSIAN_CHARSET: + return QFontDatabase::Cyrillic; + case HEBREW_CHARSET: + return QFontDatabase::Hebrew; + case ARABIC_CHARSET: + return QFontDatabase::Arabic; + case THAI_CHARSET: + return QFontDatabase::Thai; + case GB2312_CHARSET: + return QFontDatabase::SimplifiedChinese; + case CHINESEBIG5_CHARSET: + return QFontDatabase::TraditionalChinese; + case SHIFTJIS_CHARSET: + return QFontDatabase::Japanese; + case HANGUL_CHARSET: + case JOHAB_CHARSET: + return QFontDatabase::Korean; + case VIETNAMESE_CHARSET: + return QFontDatabase::Vietnamese; + case SYMBOL_CHARSET: + return QFontDatabase::Symbol; + default: + break; + } + 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(); + for (int i = 0; i < name.length(); ++i) { + if (c[i].unicode() >= 0x100) + return true; + } + return false; +} + +namespace { + +static QString readName(bool unicode, const uchar *string, int length) +{ + QString out; + if (unicode) { + // utf16 + + length /= 2; + out.resize(length); + QChar *uc = out.data(); + for (int i = 0; i < length; ++i) + uc[i] = qt_getUShort(string + 2*i); + } else { + // Apple Roman + + out.resize(length); + QChar *uc = out.data(); + for (int i = 0; i < length; ++i) + uc[i] = QLatin1Char(char(string[i])); + } + return out; +} + +enum FieldTypeValue { + FamilyId = 1, + StyleId = 2, + PreferredFamilyId = 16, + PreferredStyleId = 17, +}; + +enum PlatformFieldValue { + PlatformId_Unicode = 0, + PlatformId_Apple = 1, + PlatformId_Microsoft = 3 +}; + +QFontNames qt_getCanonicalFontNames(const uchar *table, quint32 bytes) +{ + QFontNames out; + const int NameRecordSize = 12; + const int MS_LangIdEnglish = 0x009; + + // get the name table + quint16 count; + quint16 string_offset; + const unsigned char *names; + + if (bytes < 8) + return out; + + if (qt_getUShort(table) != 0) + return out; + + count = qt_getUShort(table + 2); + string_offset = qt_getUShort(table + 4); + names = table + 6; + + if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset) + return out; + + enum PlatformIdType { + NotFound = 0, + Unicode = 1, + Apple = 2, + Microsoft = 3 + }; + + PlatformIdType idStatus[4] = { NotFound, NotFound, NotFound, NotFound }; + int ids[4] = { -1, -1, -1, -1 }; + + for (int i = 0; i < count; ++i) { + // search for the correct name entries + + quint16 platform_id = qt_getUShort(names + i*NameRecordSize); + quint16 encoding_id = qt_getUShort(names + 2 + i*NameRecordSize); + quint16 language_id = qt_getUShort(names + 4 + i*NameRecordSize); + quint16 name_id = qt_getUShort(names + 6 + i*NameRecordSize); + + PlatformIdType *idType = nullptr; + int *id = nullptr; + + switch (name_id) { + case FamilyId: + idType = &idStatus[0]; + id = &ids[0]; + break; + case StyleId: + idType = &idStatus[1]; + id = &ids[1]; + break; + case PreferredFamilyId: + idType = &idStatus[2]; + id = &ids[2]; + break; + case PreferredStyleId: + idType = &idStatus[3]; + id = &ids[3]; + break; + default: + continue; + } + + quint16 length = qt_getUShort(names + 8 + i*NameRecordSize); + quint16 offset = qt_getUShort(names + 10 + i*NameRecordSize); + if (DWORD(string_offset + offset + length) > bytes) + continue; + + if ((platform_id == PlatformId_Microsoft + && (encoding_id == 0 || encoding_id == 1)) + && ((language_id & 0x3ff) == MS_LangIdEnglish + || *idType < Microsoft)) { + *id = i; + *idType = Microsoft; + } + // not sure if encoding id 4 for Unicode is utf16 or ucs4... + else if (platform_id == PlatformId_Unicode && encoding_id < 4 && *idType < Unicode) { + *id = i; + *idType = Unicode; + } + else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0 && *idType < Apple) { + *id = i; + *idType = Apple; + } + } + + QString strings[4]; + for (int i = 0; i < 4; ++i) { + if (idStatus[i] == NotFound) + continue; + int id = ids[i]; + quint16 length = qt_getUShort(names + 8 + id * NameRecordSize); + quint16 offset = qt_getUShort(names + 10 + id * NameRecordSize); + const unsigned char *string = table + string_offset + offset; + strings[i] = readName(idStatus[i] != Apple, string, length); + } + + out.name = strings[0]; + out.style = strings[1]; + out.preferredName = strings[2]; + out.preferredStyle = strings[3]; + return out; +} + +} // namespace + +QString qt_getEnglishName(const QString &familyName, bool includeStyle) +{ + QString i18n_name; + QString faceName = familyName; + faceName.truncate(LF_FACESIZE - 1); + + HDC hdc = GetDC( 0 ); + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + faceName.toWCharArray(lf.lfFaceName); + lf.lfFaceName[faceName.size()] = 0; + lf.lfCharSet = DEFAULT_CHARSET; + HFONT hfont = CreateFontIndirect(&lf); + + if (!hfont) { + ReleaseDC(0, hdc); + return QString(); + } + + HGDIOBJ oldobj = SelectObject( hdc, hfont ); + + const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' ); + + // get the name table + unsigned char *table = 0; + + DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 ); + if ( bytes == GDI_ERROR ) { + // ### Unused variable + // int err = GetLastError(); + goto error; + } + + table = new unsigned char[bytes]; + GetFontData(hdc, name_tag, 0, table, bytes); + if ( bytes == GDI_ERROR ) + goto error; + + { + const QFontNames names = qt_getCanonicalFontNames(table, bytes); + i18n_name = names.name; + if (includeStyle) + i18n_name += QLatin1Char(' ') + names.style; + } +error: + delete [] table; + SelectObject( hdc, oldobj ); + DeleteObject( hfont ); + ReleaseDC( 0, hdc ); + + //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data()); + return i18n_name; +} + +// Note this duplicates parts of qt_getEnglishName, we should try to unify the two functions. +QFontNames qt_getCanonicalFontNames(const LOGFONT &lf) +{ + QFontNames fontNames; + HDC hdc = GetDC(0); + HFONT hfont = CreateFontIndirect(&lf); + + if (!hfont) { + ReleaseDC(0, hdc); + return fontNames; + } + + HGDIOBJ oldobj = SelectObject(hdc, hfont); + + // get the name table + QByteArray table; + const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e'); + DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0); + if (bytes != GDI_ERROR) { + table.resize(bytes); + + if (GetFontData(hdc, name_tag, 0, table.data(), bytes) != GDI_ERROR) + fontNames = qt_getCanonicalFontNames(reinterpret_cast(table.constData()), bytes); + } + + SelectObject(hdc, oldobj); + DeleteObject(hfont); + ReleaseDC(0, hdc); + + 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.utf16(), sizeof(wchar_t) * nameLength); + faceNamePtr[nameLength] = 0; + } + return faceNamePtr; +} + +namespace { + struct StoreFontPayload { + StoreFontPayload(const QString &family, + QWindowsFontDatabase *fontDatabase) + : populatedFontFamily(family) + , windowsFontDatabase(fontDatabase) + {} + + QString populatedFontFamily; + QSet foundFontAndStyles; + QWindowsFontDatabase *windowsFontDatabase; + }; +} + +static bool addFontToDatabase(QString familyName, + QString styleName, + const LOGFONT &logFont, + const TEXTMETRIC *textmetric, + const FONTSIGNATURE *signature, + int type, + StoreFontPayload *sfp) +{ + // the "@family" fonts are just the same as "family". Ignore them. + if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) + return false; + + uchar charSet = logFont.lfCharSet; + + static const int SMOOTH_SCALABLE = 0xffff; + const QString foundryName; // No such concept. + const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH); + const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); + const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); + const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight; + const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; + const bool antialias = false; + const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight); + const QFont::Stretch stretch = QFont::Unstretched; + +#ifndef QT_NO_DEBUG_OUTPUT + if (lcQpaFonts().isDebugEnabled()) { + QString message; + QTextStream str(&message); + str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf; + if (type & DEVICE_FONTTYPE) + str << " DEVICE"; + if (type & RASTER_FONTTYPE) + str << " RASTER"; + if (type & TRUETYPE_FONTTYPE) + str << " TRUETYPE"; + str << " scalable=" << scalable << " Size=" << size + << " Style=" << style << " Weight=" << weight + << " stretch=" << stretch; + qCDebug(lcQpaFonts) << message; + } +#endif + QString englishName; + QString faceName; + + QString subFamilyName; + QString subFamilyStyle; + // Look-up names registered in the font + QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); + if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) + englishName = canonicalNames.name; + if (!canonicalNames.preferredName.isEmpty()) { + subFamilyName = familyName; + subFamilyStyle = styleName; + faceName = familyName; // Remember the original name for later lookups + familyName = canonicalNames.preferredName; + styleName = canonicalNames.preferredStyle; + } + + QSupportedWritingSystems writingSystems; + if (type & TRUETYPE_FONTTYPE) { + Q_ASSERT(signature); + quint32 unicodeRange[4] = { + signature->fsUsb[0], signature->fsUsb[1], + signature->fsUsb[2], signature->fsUsb[3] + }; + quint32 codePageRange[2] = { + signature->fsCsb[0], signature->fsCsb[1] + }; + writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains + // the symbol for Baht, and Windows thus reports that it supports the Thai script. + // Since it's the default UI font on this platform, most widgets will be unable to + // display Thai text by default. As a temporary work around, we special case Segoe UI + // and remove the Thai script from its list of supported writing systems. + if (writingSystems.supported(QFontDatabase::Thai) && + familyName == QLatin1String("Segoe UI")) + writingSystems.setSupported(QFontDatabase::Thai, false); + } else { + const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); + if (ws != QFontDatabase::Any) + 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); + } + + QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, + style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(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)); + if (style != QFont::StyleItalic && styleName.isEmpty()) + QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, + QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(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)); + + if (!subFamilyName.isEmpty() && familyName != subFamilyName) { + QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight, + style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); + } + + if (!englishName.isEmpty() && englishName != familyName) + QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); + + return true; +} + +static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, + DWORD type, LPARAM lparam) +{ + const ENUMLOGFONTEX *f = reinterpret_cast(logFont); + const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName); + const QString styleName = QString::fromWCharArray(f->elfStyle); + + // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according + // to the documentation is identical to a TEXTMETRIC except for the last four + // members, which we don't use anyway + const FONTSIGNATURE *signature = nullptr; + StoreFontPayload *sfp = reinterpret_cast(lparam); + Q_ASSERT(sfp != nullptr); + if (type & TRUETYPE_FONTTYPE) { + signature = &reinterpret_cast(textmetric)->ntmFontSig; + // We get a callback for each script-type supported, but we register them all + // at once using the signature, so we only need one call to addFontToDatabase(). + FontAndStyle fontAndStyle = {familyName, styleName}; + if (sfp->foundFontAndStyles.contains(fontAndStyle)) + return 1; + sfp->foundFontAndStyles.insert(fontAndStyle); + } + addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp); + + // keep on enumerating + return 1; +} + +void QWindowsFontDatabase::populateFamily(const QString &familyName) +{ + qCDebug(lcQpaFonts) << familyName; + if (familyName.size() >= LF_FACESIZE) { + qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; + return; + } + HDC dummy = GetDC(0); + LOGFONT lf; + lf.lfCharSet = DEFAULT_CHARSET; + familyName.toWCharArray(lf.lfFaceName); + lf.lfFaceName[familyName.size()] = 0; + lf.lfPitchAndFamily = 0; + StoreFontPayload sfp(familyName, this); + EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast(&sfp), 0); + ReleaseDC(0, dummy); +} + +static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, + DWORD, LPARAM) +{ + // 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); + QPlatformFontDatabase::registerFontFamily(faceName); + // Register current font's english name as alias + const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); + if (ttf && qt_localizedName(faceName)) { + const QString englishName = qt_getEnglishName(faceName); + if (!englishName.isEmpty()) + QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); + } + } + return 1; // continue +} + +void QWindowsFontDatabase::addDefaultEUDCFont() +{ + const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)") + .stringValue(L"SystemDefaultEUDCFont"); + if (!path.isEmpty()) { + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) { + qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << path; + return; + } + + m_eudcFonts = addApplicationFont(file.readAll(), path); + } +} + +void QWindowsFontDatabase::populateFontDatabase() +{ + removeApplicationFonts(); + HDC dummy = GetDC(0); + LOGFONT lf; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfFaceName[0] = 0; + lf.lfPitchAndFamily = 0; + EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0); + ReleaseDC(0, dummy); + // Work around EnumFontFamiliesEx() not listing the system font. + QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family(); + if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily) + QPlatformFontDatabase::registerFontFamily(systemDefaultFamily); + addDefaultEUDCFont(); +} + +QWindowsFontDatabase::QWindowsFontDatabase() +{ + // Properties accessed by QWin32PrintEngine (Qt Print Support) + static const int hfontMetaTypeId = qRegisterMetaType(); + static const int logFontMetaTypeId = qRegisterMetaType(); + Q_UNUSED(hfontMetaTypeId) + Q_UNUSED(logFontMetaTypeId) + + if (lcQpaFonts().isDebugEnabled()) { + QSharedPointer d = data(); + qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: " + << d->clearTypeEnabled << "gamma: " << d->fontSmoothingGamma; + } +} + +QWindowsFontDatabase::~QWindowsFontDatabase() +{ + removeApplicationFonts(); +} + +QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) +{ + const QString faceName(static_cast(handle)); + QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName, + defaultVerticalDPI(), + data()); + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle; + return fe; +} + +QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) +{ + EmbeddedFont font(fontData); + QFontEngine *fontEngine = 0; + +#if !defined(QT_NO_DIRECTWRITE) + if (!useDirectWrite(hintingPreference)) +#endif + { + GUID guid; + CoCreateGuid(&guid); + +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wstrict-aliasing") + QString uniqueFamilyName = QLatin1Char('f') + + QString::number(guid.Data1, 36) + QLatin1Char('-') + + QString::number(guid.Data2, 36) + QLatin1Char('-') + + QString::number(guid.Data3, 36) + QLatin1Char('-') + + QString::number(*reinterpret_cast(guid.Data4), 36); +QT_WARNING_POP + + QString actualFontName = font.changeFamilyName(uniqueFamilyName); + if (actualFontName.isEmpty()) { + qWarning("%s: Can't change family name of font", __FUNCTION__); + return 0; + } + + DWORD count = 0; + QByteArray newFontData = font.data(); + HANDLE fontHandle = + AddFontMemResourceEx(const_cast(newFontData.constData()), + DWORD(newFontData.size()), 0, &count); + if (count == 0 && fontHandle != 0) { + RemoveFontMemResourceEx(fontHandle); + fontHandle = 0; + } + + if (fontHandle == 0) { + qWarning("%s: AddFontMemResourceEx failed", __FUNCTION__); + } else { + QFontDef request; + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + request.styleStrategy = QFont::PreferMatch; + request.hintingPreference = hintingPreference; + request.stretch = QFont::Unstretched; + + fontEngine = QWindowsFontDatabase::createEngine(request, QString(), + defaultVerticalDPI(), + data()); + + if (fontEngine) { + if (request.family != fontEngine->fontDef.family) { + qWarning("%s: Failed to load font. Got fallback instead: %s", + __FUNCTION__, qPrintable(fontEngine->fontDef.family)); + if (fontEngine->ref.loadRelaxed() == 0) + delete fontEngine; + fontEngine = 0; + } else { + Q_ASSERT(fontEngine->ref.loadRelaxed() == 0); + + // Override the generated font name + switch (fontEngine->type()) { + case QFontEngine::Win: + static_cast(fontEngine)->setUniqueFamilyName(uniqueFamilyName); + fontEngine->fontDef.family = actualFontName; + break; +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) + case QFontEngine::DirectWrite: + static_cast(fontEngine)->setUniqueFamilyName(uniqueFamilyName); + fontEngine->fontDef.family = actualFontName; + break; +#endif // directwrite && direct2d + + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine."); + } + + UniqueFontData uniqueData; + uniqueData.handle = fontHandle; + uniqueData.refCount.ref(); + m_uniqueFontData[uniqueFamilyName] = uniqueData; + } + } else { + RemoveFontMemResourceEx(fontHandle); + } + } + + // Get style and weight info + if (fontEngine != nullptr) + font.updateFromOS2Table(fontEngine); + } +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) + else { + fontEngine = QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference); + } +#endif // directwrite && direct2d + + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine; + return fontEngine; +} + +static QList getTrueTypeFontOffsets(const uchar *fontData) +{ + QList offsets; + const quint32 headerTag = *reinterpret_cast(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')) + return offsets; + offsets << 0; + return offsets; + } + const quint32 numFonts = qFromBigEndian(fontData + 8); + for (uint i = 0; i < numFonts; ++i) { + offsets << qFromBigEndian(fontData + 12 + i * 4); + } + return offsets; +} + +static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length) +{ + const quint16 numTables = qFromBigEndian(data + 4); + for (uint i = 0; i < numTables; ++i) { + const quint32 offset = 12 + 16 * i; + if (*reinterpret_cast(data + offset) == tag) { + *table = fileBegin + qFromBigEndian(data + offset + 8); + *length = qFromBigEndian(data + offset + 12); + return; + } + } + *table = 0; + *length = 0; + return; +} + +static void getFamiliesAndSignatures(const QByteArray &fontData, + QList *families, + QVector *signatures, + QVector *values) +{ + const uchar *data = reinterpret_cast(fontData.constData()); + + QList offsets = getTrueTypeFontOffsets(data); + if (offsets.isEmpty()) + return; + + for (int i = 0; i < offsets.count(); ++i) { + const uchar *font = data + offsets.at(i); + const uchar *table; + quint32 length; + getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); + if (!table) + continue; + QFontNames names = qt_getCanonicalFontNames(table, length); + if (names.name.isEmpty()) + continue; + + families->append(std::move(names)); + + if (values || signatures) + getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); + + if (values) { + QFontValues fontValues; + if (table && length >= 64) { + // Read in some details about the font, offset calculated based on the specification + fontValues.weight = qFromBigEndian(table + 4); + + quint16 fsSelection = qFromBigEndian(table + 62); + fontValues.isItalic = (fsSelection & 1) != 0; + fontValues.isUnderlined = (fsSelection & (1 << 1)) != 0; + fontValues.isOverstruck = (fsSelection & (1 << 4)) != 0; + } + values->append(std::move(fontValues)); + } + + if (signatures) { + FONTSIGNATURE signature; + if (table && length >= 86) { + // Offsets taken from OS/2 table in the TrueType spec + signature.fsUsb[0] = qFromBigEndian(table + 42); + signature.fsUsb[1] = qFromBigEndian(table + 46); + signature.fsUsb[2] = qFromBigEndian(table + 50); + signature.fsUsb[3] = qFromBigEndian(table + 54); + + signature.fsCsb[0] = qFromBigEndian(table + 78); + signature.fsCsb[1] = qFromBigEndian(table + 82); + } else { + memset(&signature, 0, sizeof(signature)); + } + signatures->append(signature); + } + } +} + +QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont) +{ + WinApplicationFont font; + font.fileName = fileName; + QVector signatures; + QVector fontValues; + QList families; + QStringList familyNames; + + if (!fontData.isEmpty()) { + getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues); + if (families.isEmpty()) + return familyNames; + + DWORD dummy = 0; + font.handle = + AddFontMemResourceEx(const_cast(fontData.constData()), + DWORD(fontData.size()), 0, &dummy); + if (font.handle == 0) + return QStringList(); + + // Memory fonts won't show up in enumeration, so do add them the hard way. + for (int j = 0; j < families.count(); ++j) { + const auto &family = families.at(j); + const QString &familyName = family.name; + const QString &styleName = family.style; + familyNames << familyName; + HDC hdc = GetDC(0); + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size())); + lf.lfCharSet = DEFAULT_CHARSET; + const QFontValues &values = fontValues.at(j); + lf.lfWeight = values.weight; + if (values.isItalic) + lf.lfItalic = TRUE; + if (values.isOverstruck) + lf.lfStrikeOut = TRUE; + if (values.isUnderlined) + lf.lfUnderline = TRUE; + HFONT hfont = CreateFontIndirect(&lf); + HGDIOBJ oldobj = SelectObject(hdc, hfont); + + if (applicationFont != nullptr) { + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal; + properties.weight = QPlatformFontDatabase::weightFromInteger(values.weight); + properties.familyName = familyName; + properties.styleName = styleName; + + applicationFont->properties.append(properties); + } + + TEXTMETRIC textMetrics; + GetTextMetrics(hdc, &textMetrics); + + StoreFontPayload sfp(familyName, this); + addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j), + TRUETYPE_FONTTYPE, &sfp); + + SelectObject(hdc, oldobj); + DeleteObject(hfont); + ReleaseDC(0, hdc); + } + } else { + QFile f(fileName); + if (!f.open(QIODevice::ReadOnly)) + return QStringList(); + QByteArray data = f.readAll(); + f.close(); + + + getFamiliesAndSignatures(data, &families, nullptr, applicationFont != nullptr ? &fontValues : nullptr); + + if (families.isEmpty()) + return QStringList(); + + if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0) + return QStringList(); + + font.handle = 0; + + // Fonts based on files are added via populate, as they will show up in font enumeration. + for (int j = 0; j < families.count(); ++j) { + const QString familyName = families.at(j).name; + familyNames << familyName; + + if (applicationFont != nullptr) { + const QString &styleName = families.at(j).style; + const QFontValues &values = fontValues.at(j); + + QFontDatabasePrivate::ApplicationFont::Properties properties; + properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal; + properties.weight = QPlatformFontDatabase::weightFromInteger(values.weight); + properties.familyName = familyName; + properties.styleName = styleName; + + applicationFont->properties.append(properties); + } + + populateFamily(familyName); + } + } + + m_applicationFonts << font; + + return familyNames; +} + +void QWindowsFontDatabase::removeApplicationFonts() +{ + for (const WinApplicationFont &font : qAsConst(m_applicationFonts)) { + if (font.handle) { + RemoveFontMemResourceEx(font.handle); + } else { + RemoveFontResourceExW(reinterpret_cast(font.fileName.utf16()), + FR_PRIVATE, nullptr); + } + } + m_applicationFonts.clear(); + m_eudcFonts.clear(); +} + +void QWindowsFontDatabase::releaseHandle(void *handle) +{ + const QChar *faceName = reinterpret_cast(handle); + delete[] faceName; +} + +QString QWindowsFontDatabase::fontDir() const +{ + const QString result = QPlatformFontDatabase::fontDir(); + qCDebug(lcQpaFonts) << __FUNCTION__ << result; + return result; +} + +bool QWindowsFontDatabase::fontsAlwaysScalable() const +{ + return false; +} + +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); + } + } +} + +void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont) +{ + if (m_uniqueFontData.contains(uniqueFont)) + m_uniqueFontData[uniqueFont].refCount.ref(); +} + +QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const +{ + QStringList result; + result.append(familyForStyleHint(styleHint)); + result.append(m_eudcFonts); + result.append(extraTryFontsForFamily(family)); + result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); + + qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint + << script << result; + return result; +} + + +QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const QString &faceName, + int dpi, + const QSharedPointer &data) +{ + QFontEngine *fe = 0; + + LOGFONT lf = fontDefToLOGFONT(request, faceName); + const bool preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY; + + if (request.stretch != 100) { + HFONT hfont = CreateFontIndirect(&lf); + if (!hfont) { + qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); + hfont = QWindowsFontDatabase::systemFont(); + } + + HGDIOBJ oldObj = SelectObject(data->hdc, hfont); + TEXTMETRIC tm; + if (!GetTextMetrics(data->hdc, &tm)) + qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__); + else + lf.lfWidth = tm.tmAveCharWidth * request.stretch / 100; + SelectObject(data->hdc, oldObj); + + DeleteObject(hfont); + } + +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) + if (data->directWriteFactory != nullptr) { + const QString fam = QString::fromWCharArray(lf.lfFaceName); + const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); + if (nameSubstitute != fam) { + const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); + memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); + lf.lfFaceName[nameSubstituteLength] = 0; + } + + HFONT hfont = CreateFontIndirect(&lf); + if (!hfont) { + qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); + } else { + HGDIOBJ oldFont = SelectObject(data->hdc, hfont); + + const QFont::HintingPreference hintingPreference = + static_cast(request.hintingPreference); + bool useDw = useDirectWrite(hintingPreference, fam); + + IDWriteFontFace *directWriteFontFace = NULL; + HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace); + if (SUCCEEDED(hr)) { + bool isColorFont = false; +#if QT_CONFIG(direct2d) + IDWriteFontFace2 *directWriteFontFace2 = nullptr; + if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2), + reinterpret_cast(&directWriteFontFace2)))) { + if (directWriteFontFace2->IsColorFont()) + isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0; + + directWriteFontFace2->Release(); + } +#endif // direct2d + useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont); + qCDebug(lcQpaFonts) << __FUNCTION__ << request.family << request.pointSize + << "pt" << "hintingPreference=" << hintingPreference << "color=" << isColorFont + << dpi << "dpi" << "useDirectWrite=" << useDw; + if (useDw) { + QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, + request.pixelSize, + data); + + wchar_t n[64]; + GetTextFace(data->hdc, 64, n); + + QFontDef fontDef = request; + fontDef.family = QString::fromWCharArray(n); + + if (isColorFont) + fedw->glyphFormat = QFontEngine::Format_ARGB; + fedw->initFontInfo(fontDef, dpi); + fe = fedw; + } + directWriteFontFace->Release(); + } else if (useDw) { + const QString errorString = qt_error_string(int(hr)); + qWarning().noquote().nospace() << "DirectWrite: CreateFontFaceFromHDC() failed (" + << errorString << ") for " << request << ' ' << lf << " dpi=" << dpi; + } + + SelectObject(data->hdc, oldFont); + DeleteObject(hfont); + } + } +#endif // directwrite direct2d + + if (!fe) { + QWindowsFontEngine *few = new QWindowsFontEngine(request.family, lf, data); + if (preferClearTypeAA) + few->glyphFormat = QFontEngine::Format_A32; + few->initFontInfo(request, dpi); + fe = few; + } + + return fe; +} + +bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const +{ + return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family); +} + +QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsfontdatabase_ft.cpp b/src/gui/text/windows/qwindowsfontdatabase_ft.cpp new file mode 100644 index 0000000000..cde20eebc2 --- /dev/null +++ b/src/gui/text/windows/qwindowsfontdatabase_ft.cpp @@ -0,0 +1,444 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#include "qwindowsfontdatabase_ft_p.h" +#include "qwindowsfontdatabase_p.h" + +#include + +#include +#include FT_TRUETYPE_TABLES_H + +#include +#include +#include +#if QT_CONFIG(regularexpression) +#include +#endif +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) +{ + switch (charSet) { + case ANSI_CHARSET: + case EASTEUROPE_CHARSET: + case BALTIC_CHARSET: + case TURKISH_CHARSET: + return QFontDatabase::Latin; + case GREEK_CHARSET: + return QFontDatabase::Greek; + case RUSSIAN_CHARSET: + return QFontDatabase::Cyrillic; + case HEBREW_CHARSET: + return QFontDatabase::Hebrew; + case ARABIC_CHARSET: + return QFontDatabase::Arabic; + case THAI_CHARSET: + return QFontDatabase::Thai; + case GB2312_CHARSET: + return QFontDatabase::SimplifiedChinese; + case CHINESEBIG5_CHARSET: + return QFontDatabase::TraditionalChinese; + case SHIFTJIS_CHARSET: + return QFontDatabase::Japanese; + case HANGUL_CHARSET: + case JOHAB_CHARSET: + return QFontDatabase::Korean; + case VIETNAMESE_CHARSET: + return QFontDatabase::Vietnamese; + case SYMBOL_CHARSET: + return QFontDatabase::Symbol; + default: + break; + } + return QFontDatabase::Any; +} + +static FontFile * createFontFile(const QString &fileName, int index) +{ + FontFile *fontFile = new FontFile; + fontFile->fileName = fileName; + fontFile->indexValue = index; + return fontFile; +} + +namespace { +struct FontKey +{ + QString fileName; + QStringList fontNames; +}; +} // namespace + +typedef QVector FontKeys; + +static FontKeys &fontKeys() +{ + static FontKeys result; + if (result.isEmpty()) { + const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), + QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") }; + for (const auto key : keys) { + const QSettings fontRegistry(key, QSettings::NativeFormat); + const QStringList allKeys = fontRegistry.allKeys(); + const QString trueType = QStringLiteral("(TrueType)"); +#if QT_CONFIG(regularexpression) + const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+")); + Q_ASSERT(sizeListMatch.isValid()); +#endif + const int size = allKeys.size(); + result.reserve(result.size() + size); + for (int i = 0; i < size; ++i) { + FontKey fontKey; + const QString ®istryFontKey = allKeys.at(i); + fontKey.fileName = fontRegistry.value(registryFontKey).toString(); + QString realKey = registryFontKey; + realKey.remove(trueType); +#if QT_CONFIG(regularexpression) + realKey.remove(sizeListMatch); +#endif + const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&')); + fontKey.fontNames.reserve(fontNames.size()); + for (const QStringRef &fontName : fontNames) + fontKey.fontNames.append(fontName.trimmed().toString()); + result.append(fontKey); + } + } + } + return result; +} + +static const FontKey *findFontKey(const QString &name, int *indexIn = nullptr) +{ + const FontKeys &keys = fontKeys(); + for (auto it = keys.constBegin(), cend = keys.constEnd(); it != cend; ++it) { + const int index = it->fontNames.indexOf(name); + if (index >= 0) { + if (indexIn) + *indexIn = index; + return &(*it); + } + } + if (indexIn) + *indexIn = -1; + return nullptr; +} + +static bool addFontToDatabase(QString familyName, + QString styleName, + const QString &fullName, + const LOGFONT &logFont, + const TEXTMETRIC *textmetric, + const FONTSIGNATURE *signature, + int type) +{ + // the "@family" fonts are just the same as "family". Ignore them. + if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) + return false; + + uchar charSet = logFont.lfCharSet; + + static const int SMOOTH_SCALABLE = 0xffff; + const QString foundryName; // No such concept. + const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH); + const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); + const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); + const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight; + const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; + const bool antialias = false; + const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight); + const QFont::Stretch stretch = QFont::Unstretched; + +#ifndef QT_NO_DEBUG_STREAM + if (lcQpaFonts().isDebugEnabled()) { + QString message; + QTextStream str(&message); + str << __FUNCTION__ << ' ' << familyName << "::" << fullName << ' ' << charSet << " TTF=" << ttf; + if (type & DEVICE_FONTTYPE) + str << " DEVICE"; + if (type & RASTER_FONTTYPE) + str << " RASTER"; + if (type & TRUETYPE_FONTTYPE) + str << " TRUETYPE"; + str << " scalable=" << scalable << " Size=" << size + << " Style=" << style << " Weight=" << weight + << " stretch=" << stretch; + qCDebug(lcQpaFonts) << message; + } +#endif + + QString englishName; + QString faceName = familyName; + + QString subFamilyName; + QString subFamilyStyle; + // Look-up names registered in the font + QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); + if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) + englishName = canonicalNames.name; + if (!canonicalNames.preferredName.isEmpty()) { + subFamilyName = familyName; + subFamilyStyle = styleName; + familyName = canonicalNames.preferredName; + styleName = canonicalNames.preferredStyle; + } + + QSupportedWritingSystems writingSystems; + if (type & TRUETYPE_FONTTYPE) { + Q_ASSERT(signature); + quint32 unicodeRange[4] = { + signature->fsUsb[0], signature->fsUsb[1], + signature->fsUsb[2], signature->fsUsb[3] + }; + quint32 codePageRange[2] = { + signature->fsCsb[0], signature->fsCsb[1] + }; + writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains + // the symbol for Baht, and Windows thus reports that it supports the Thai script. + // Since it's the default UI font on this platform, most widgets will be unable to + // display Thai text by default. As a temporary work around, we special case Segoe UI + // and remove the Thai script from its list of supported writing systems. + if (writingSystems.supported(QFontDatabase::Thai) && + faceName == QLatin1String("Segoe UI")) + writingSystems.setSupported(QFontDatabase::Thai, false); + } else { + const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); + if (ws != QFontDatabase::Any) + writingSystems.setSupported(ws); + } + + int index = 0; + const FontKey *key = findFontKey(fullName, &index); + if (!key) { + // On non-English locales, the styles of the font may be localized in enumeration, but + // not in the registry. + QLocale systemLocale = QLocale::system(); + if (systemLocale.language() != QLocale::C + && systemLocale.language() != QLocale::English + && styleName != QLatin1String("Italic") + && styleName != QLatin1String("Bold")) { + key = findFontKey(qt_getEnglishName(fullName, true), &index); + } + if (!key) + key = findFontKey(faceName, &index); + if (!key && !englishName.isEmpty()) + key = findFontKey(englishName, &index); + if (!key) + return false; + } + QString value = key->fileName; + if (value.isEmpty()) + return false; + + if (!QDir::isAbsolutePath(value)) + value.prepend(QFile::decodeName(qgetenv("windir") + "\\Fonts\\")); + + QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, + antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); + + // 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(value, index)); + + if (style != QFont::StyleItalic && styleName.isEmpty()) + QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, QFont::StyleItalic, stretch, + antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); + + 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(value, index)); + + if (!subFamilyName.isEmpty() && familyName != subFamilyName) { + QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight, + style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); + } + + if (!englishName.isEmpty() && englishName != familyName) + QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); + + return true; +} + +static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, + DWORD type, LPARAM lparam) +{ + const ENUMLOGFONTEX *f = reinterpret_cast(logFont); + const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName); + const QString styleName = QString::fromWCharArray(f->elfStyle); + const QString fullName = QString::fromWCharArray(f->elfFullName); + + // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according + // to the documentation is identical to a TEXTMETRIC except for the last four + // members, which we don't use anyway + const FONTSIGNATURE *signature = nullptr; + if (type & TRUETYPE_FONTTYPE) { + signature = &reinterpret_cast(textmetric)->ntmFontSig; + // We get a callback for each script-type supported, but we register them all + // at once using the signature, so we only need one call to addFontToDatabase(). + QSet *foundFontAndStyles = reinterpret_cast *>(lparam); + FontAndStyle fontAndStyle = {faceName, styleName}; + if (foundFontAndStyles->contains(fontAndStyle)) + return 1; + foundFontAndStyles->insert(fontAndStyle); + } + addFontToDatabase(faceName, styleName, fullName, *logFont, textmetric, signature, type); + + // keep on enumerating + return 1; +} + +/*! + \brief Populate font database using EnumFontFamiliesEx(). + + Normally, leaving the name empty should enumerate + all fonts, however, system fonts like "MS Shell Dlg 2" + are only found when specifying the name explicitly. +*/ + +void QWindowsFontDatabaseFT::populateFamily(const QString &familyName) +{ + qCDebug(lcQpaFonts) << familyName; + if (familyName.size() >= LF_FACESIZE) { + qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; + return; + } + HDC dummy = GetDC(0); + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + familyName.toWCharArray(lf.lfFaceName); + lf.lfFaceName[familyName.size()] = 0; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfPitchAndFamily = 0; + QSet foundFontAndStyles; + EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast(&foundFontAndStyles), 0); + ReleaseDC(0, dummy); +} + +// Delayed population of font families + +static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, + DWORD, LPARAM) +{ + const ENUMLOGFONTEX *f = reinterpret_cast(logFont); + // the "@family" fonts are just the same as "family". Ignore them. + const wchar_t *faceNameW = f->elfLogFont.lfFaceName; + if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) { + // Register only font families for which a font file exists for delayed population + const bool ttf = textmetric->tmPitchAndFamily & TMPF_TRUETYPE; + const QString faceName = QString::fromWCharArray(faceNameW); + const FontKey *key = findFontKey(faceName); + if (!key) { + key = findFontKey(QString::fromWCharArray(f->elfFullName)); + if (!key && ttf && qt_localizedName(faceName)) + key = findFontKey(qt_getEnglishName(faceName)); + } + if (key) { + QPlatformFontDatabase::registerFontFamily(faceName); + // Register current font's english name as alias + if (ttf && qt_localizedName(faceName)) { + const QString englishName = qt_getEnglishName(faceName); + if (!englishName.isEmpty()) + QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); + } + } + } + return 1; // continue +} + +void QWindowsFontDatabaseFT::populateFontDatabase() +{ + HDC dummy = GetDC(0); + LOGFONT lf; + lf.lfCharSet = DEFAULT_CHARSET; + lf.lfFaceName[0] = 0; + lf.lfPitchAndFamily = 0; + EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0); + ReleaseDC(0, dummy); + // Work around EnumFontFamiliesEx() not listing the system font + QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family(); + if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily) + QPlatformFontDatabase::registerFontFamily(systemDefaultFamily); +} + +QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle) +{ + QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontDef, handle); + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.family << fe << handle; + return fe; +} + +QFontEngine *QWindowsFontDatabaseFT::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) +{ + QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference); + qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe; + return fe; +} + +QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const +{ + QStringList result; + result.append(QWindowsFontDatabaseBase::familyForStyleHint(styleHint)); + result.append(QWindowsFontDatabaseBase::extraTryFontsForFamily(family)); + result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script)); + + qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint + << script << result; + + return result; +} +QString QWindowsFontDatabaseFT::fontDir() const +{ + const QString result = QLatin1String(qgetenv("windir")) + QLatin1String("/Fonts");//QPlatformFontDatabase::fontDir(); + qCDebug(lcQpaFonts) << __FUNCTION__ << result; + return result; +} + +QFont QWindowsFontDatabaseFT::defaultFont() const +{ + return QWindowsFontDatabase::systemDefaultFont(); +} + +QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsfontdatabase_ft_p.h b/src/gui/text/windows/qwindowsfontdatabase_ft_p.h new file mode 100644 index 0000000000..af0b1d7077 --- /dev/null +++ b/src/gui/text/windows/qwindowsfontdatabase_ft_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTDATABASEFT_H +#define QWINDOWSFONTDATABASEFT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QWindowsFontDatabaseFT : public QFreeTypeFontDatabase +{ +public: + void populateFontDatabase() override; + void populateFamily(const QString &familyName) 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; + + QString fontDir() const override; + QFont defaultFont() const override; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSFONTDATABASEFT_H diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h new file mode 100644 index 0000000000..b870d6c4a0 --- /dev/null +++ b/src/gui/text/windows/qwindowsfontdatabase_p.h @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTDATABASE_H +#define QWINDOWSFONTDATABASE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qwindowsfontdatabasebase_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDebug; + +class Q_GUI_EXPORT QWindowsFontDatabase : public QWindowsFontDatabaseBase +{ + Q_DISABLE_COPY_MOVE(QWindowsFontDatabase) +public: + enum FontOptions { + // Relevant bits from QWindowsIntegration::Options + DontUseDirectWriteFonts = 0x40, + DontUseColorFonts = 0x80 + }; + + QWindowsFontDatabase(); + ~QWindowsFontDatabase() override; + + void ensureFamilyPopulated(const QString &familyName); + + void populateFontDatabase() override; + void populateFamily(const QString &familyName) 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 *applicationFont = nullptr) override; + void releaseHandle(void *handle) override; + QString fontDir() const override; + + QFont defaultFont() const override { return systemDefaultFont(); } + bool fontsAlwaysScalable() const override; + void derefUniqueFont(const QString &uniqueFont); + void refUniqueFont(const QString &uniqueFont); + bool isPrivateFontFamily(const QString &family) const override; + + static QFontEngine *createEngine(const QFontDef &request, const QString &faceName, + int dpi, + const QSharedPointer &data); + + static qreal fontSmoothingGamma(); + + static void setFontOptions(unsigned options); + static unsigned fontOptions(); + +#ifndef QT_NO_DEBUG_STREAM + static void debugFormat(QDebug &d, const LOGFONT &lf); +#endif // !QT_NO_DEBUG_STREAM + +private: + void removeApplicationFonts(); + void addDefaultEUDCFont(); + + struct WinApplicationFont { + HANDLE handle; + QString fileName; + }; + + QList m_applicationFonts; + + struct UniqueFontData { + HANDLE handle; + QAtomicInt refCount; + }; + + QMap m_uniqueFontData; + + static unsigned m_fontOptions; + QStringList m_eudcFonts; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug, const QFontDef &def); +#endif + +inline quint16 qt_getUShort(const unsigned char *p) +{ + quint16 val; + val = *p++ << 8; + val |= *p; + + return val; +} + +struct QFontNames +{ + QString name; // e.g. "DejaVu Sans Condensed" + QString style; // e.g. "Italic" + QString preferredName; // e.g. "DejaVu Sans" + QString preferredStyle; // e.g. "Condensed Italic" +}; + +struct QFontValues +{ + quint16 weight = 0; + bool isItalic = false; + bool isOverstruck = false; + bool isUnderlined = false; +}; + +bool qt_localizedName(const QString &name); +QString qt_getEnglishName(const QString &familyName, bool includeStyle = false); +QFontNames qt_getCanonicalFontNames(const LOGFONT &lf); + +struct FontAndStyle { + QString font; + QString style; + + friend inline bool operator==(const FontAndStyle &lhs, const FontAndStyle &rhs) noexcept + { return lhs.font == rhs.font && lhs.style == rhs.style; } + friend inline bool operator!=(const FontAndStyle &lhs, const FontAndStyle &rhs) noexcept + { return !operator==(lhs, rhs); } +}; +inline size_t qHash(const FontAndStyle &key, size_t seed) noexcept +{ + return qHashMulti(seed, key.font, key.style); +} + +QT_END_NAMESPACE + +#endif // QWINDOWSFONTDATABASE_H diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp new file mode 100644 index 0000000000..6c32b40549 --- /dev/null +++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp @@ -0,0 +1,971 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#include "qwindowsfontdatabasebase_p.h" +#include "qwindowsfontdatabase_p.h" + +#include +#include +#include + +#if !defined(QT_NO_DIRECTWRITE) +# if defined(QT_USE_DIRECTWRITE3) +# include +# elif defined(QT_USE_DIRECTWRITE2) +# include +# else +# include +# endif +# include +# include "qwindowsfontenginedirectwrite_p.h" +#endif + +QT_BEGIN_NAMESPACE + +// Helper classes for creating font engines directly from font data +namespace { + +# pragma pack(1) + + // Common structure for all formats of the "name" table + struct NameTable + { + quint16 format; + quint16 count; + quint16 stringOffset; + }; + + struct NameRecord + { + quint16 platformID; + quint16 encodingID; + quint16 languageID; + quint16 nameID; + quint16 length; + quint16 offset; + }; + + struct OffsetSubTable + { + quint32 scalerType; + quint16 numTables; + quint16 searchRange; + quint16 entrySelector; + quint16 rangeShift; + }; + + struct TableDirectory : public QWindowsFontDatabaseBase::FontTable + { + quint32 identifier; + quint32 checkSum; + quint32 offset; + quint32 length; + }; + + struct OS2Table + { + quint16 version; + qint16 avgCharWidth; + quint16 weightClass; + quint16 widthClass; + quint16 type; + qint16 subscriptXSize; + qint16 subscriptYSize; + qint16 subscriptXOffset; + qint16 subscriptYOffset; + qint16 superscriptXSize; + qint16 superscriptYSize; + qint16 superscriptXOffset; + qint16 superscriptYOffset; + qint16 strikeOutSize; + qint16 strikeOutPosition; + qint16 familyClass; + quint8 panose[10]; + quint32 unicodeRanges[4]; + quint8 vendorID[4]; + quint16 selection; + quint16 firstCharIndex; + quint16 lastCharIndex; + qint16 typoAscender; + qint16 typoDescender; + qint16 typoLineGap; + quint16 winAscent; + quint16 winDescent; + quint32 codepageRanges[2]; + qint16 height; + qint16 capHeight; + quint16 defaultChar; + quint16 breakChar; + quint16 maxContext; + }; + +# pragma pack() + +} // Anonymous namespace + +QWindowsFontDatabaseBase::FontTable *QWindowsFontDatabaseBase::EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName) +{ + Q_ASSERT(tagName.size() == 4); + quint32 tagId = *(reinterpret_cast(tagName.constData())); + const size_t fontDataSize = m_fontData.size(); + if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable))) + return nullptr; + + OffsetSubTable *offsetSubTable = reinterpret_cast(m_fontData.data()); + TableDirectory *tableDirectory = reinterpret_cast(offsetSubTable + 1); + + const size_t tableCount = qFromBigEndian(offsetSubTable->numTables); + if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) + return nullptr; + + TableDirectory *tableDirectoryEnd = tableDirectory + tableCount; + for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) { + if (entry->identifier == tagId) + return entry; + } + + return nullptr; +} + +QString QWindowsFontDatabaseBase::EmbeddedFont::familyName(QWindowsFontDatabaseBase::FontTable *directoryEntry) +{ + QString name; + + TableDirectory *nameTableDirectoryEntry = static_cast(directoryEntry); + if (nameTableDirectoryEntry == nullptr) + nameTableDirectoryEntry = static_cast(tableDirectoryEntry("name")); + + if (nameTableDirectoryEntry != nullptr) { + quint32 offset = qFromBigEndian(nameTableDirectoryEntry->offset); + if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable))) + return QString(); + + NameTable *nameTable = reinterpret_cast(m_fontData.data() + offset); + NameRecord *nameRecord = reinterpret_cast(nameTable + 1); + + quint16 nameTableCount = qFromBigEndian(nameTable->count); + if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount)) + return QString(); + + for (int i = 0; i < nameTableCount; ++i, ++nameRecord) { + if (qFromBigEndian(nameRecord->nameID) == 1 + && qFromBigEndian(nameRecord->platformID) == 3 // Windows + && qFromBigEndian(nameRecord->languageID) == 0x0409) { // US English + quint16 stringOffset = qFromBigEndian(nameTable->stringOffset); + quint16 nameOffset = qFromBigEndian(nameRecord->offset); + quint16 nameLength = qFromBigEndian(nameRecord->length); + + if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength)) + return QString(); + + const void *ptr = reinterpret_cast(nameTable) + + stringOffset + + nameOffset; + + const quint16 *s = reinterpret_cast(ptr); + const quint16 *e = s + nameLength / sizeof(quint16); + while (s != e) + name += QChar( qFromBigEndian(*s++)); + break; + } + } + } + + return name; +} + +void QWindowsFontDatabaseBase::EmbeddedFont::updateFromOS2Table(QFontEngine *fontEngine) +{ + TableDirectory *os2TableEntry = static_cast(tableDirectoryEntry("OS/2")); + if (os2TableEntry != nullptr) { + const OS2Table *os2Table = + reinterpret_cast(m_fontData.constData() + + qFromBigEndian(os2TableEntry->offset)); + + bool italic = qFromBigEndian(os2Table->selection) & (1 << 0); + bool oblique = qFromBigEndian(os2Table->selection) & (1 << 9); + + if (italic) + fontEngine->fontDef.style = QFont::StyleItalic; + else if (oblique) + fontEngine->fontDef.style = QFont::StyleOblique; + else + fontEngine->fontDef.style = QFont::StyleNormal; + + fontEngine->fontDef.weight = QPlatformFontDatabase::weightFromInteger(qFromBigEndian(os2Table->weightClass)); + } +} + +QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(const QString &newFamilyName) +{ + TableDirectory *nameTableDirectoryEntry = static_cast(tableDirectoryEntry("name")); + if (nameTableDirectoryEntry == nullptr) + return QString(); + + QString oldFamilyName = familyName(nameTableDirectoryEntry); + + // Reserve size for name table header, five required name records and string + const int requiredRecordCount = 5; + quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 }; + + int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount; + int newFamilyNameSize = newFamilyName.size() * int(sizeof(quint16)); + + const QString regularString = QString::fromLatin1("Regular"); + int regularStringSize = regularString.size() * int(sizeof(quint16)); + + // Align table size of table to 32 bits (pad with 0) + int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4; + + QByteArray newNameTable(fullSize, char(0)); + + { + NameTable *nameTable = reinterpret_cast(newNameTable.data()); + nameTable->count = qbswap(requiredRecordCount); + nameTable->stringOffset = qbswap(sizeOfHeader); + + NameRecord *nameRecord = reinterpret_cast(nameTable + 1); + for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) { + nameRecord->nameID = qbswap(nameIds[i]); + nameRecord->encodingID = qbswap(1); + nameRecord->languageID = qbswap(0x0409); + nameRecord->platformID = qbswap(3); + nameRecord->length = qbswap(newFamilyNameSize); + + // Special case for sub-family + if (nameIds[i] == 4) { + nameRecord->offset = qbswap(newFamilyNameSize); + nameRecord->length = qbswap(regularStringSize); + } + } + + // nameRecord now points to string data + quint16 *stringStorage = reinterpret_cast(nameRecord); + const quint16 *sourceString = newFamilyName.utf16(); + for (int i = 0; i < newFamilyName.size(); ++i) + stringStorage[i] = qbswap(sourceString[i]); + stringStorage += newFamilyName.size(); + + sourceString = regularString.utf16(); + for (int i = 0; i < regularString.size(); ++i) + stringStorage[i] = qbswap(sourceString[i]); + } + + quint32 *p = reinterpret_cast(newNameTable.data()); + quint32 *tableEnd = reinterpret_cast(newNameTable.data() + fullSize); + + quint32 checkSum = 0; + while (p < tableEnd) + checkSum += qFromBigEndian(*(p++)); + + nameTableDirectoryEntry->checkSum = qbswap(checkSum); + nameTableDirectoryEntry->offset = qbswap(m_fontData.size()); + nameTableDirectoryEntry->length = qbswap(fullSize); + + m_fontData.append(newNameTable); + + return oldFamilyName; +} + +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) + +namespace { + class DirectWriteFontFileStream: public IDWriteFontFileStream + { + Q_DISABLE_COPY(DirectWriteFontFileStream) + public: + DirectWriteFontFileStream(const QByteArray &fontData) + : m_fontData(fontData) + , m_referenceCount(0) + { + } + virtual ~DirectWriteFontFileStream() + { + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset, + UINT64 fragmentSize, OUT void **fragmentContext); + void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext); + HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize); + HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime); + + private: + QByteArray m_fontData; + ULONG m_referenceCount; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment( + const void **fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void **fragmentContext) + { + *fragmentContext = NULL; + if (fileOffset + fragmentSize <= quint64(m_fontData.size())) { + *fragmentStart = m_fontData.data() + fileOffset; + return S_OK; + } else { + *fragmentStart = NULL; + return E_FAIL; + } + } + + void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *) + { + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize) + { + *fileSize = m_fontData.size(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) + { + *lastWriteTime = 0; + return E_NOTIMPL; + } + + class DirectWriteFontFileLoader: public IDWriteFontFileLoader + { + public: + DirectWriteFontFileLoader() : m_referenceCount(0) {} + virtual ~DirectWriteFontFileLoader() + { + } + + inline void addKey(const void *key, const QByteArray &fontData) + { + Q_ASSERT(!m_fontDatas.contains(key)); + m_fontDatas.insert(key, fontData); + } + + inline void removeKey(const void *key) + { + m_fontDatas.remove(key); + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + OUT IDWriteFontFileStream **fontFileStream); + + private: + ULONG m_referenceCount; + QHash m_fontDatas; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, + void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey( + void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + IDWriteFontFileStream **fontFileStream) + { + Q_UNUSED(fontFileReferenceKeySize); + + if (fontFileReferenceKeySize != sizeof(const void *)) { + qWarning("%s: Wrong key size", __FUNCTION__); + return E_FAIL; + } + + const void *key = *reinterpret_cast(fontFileReferenceKey); + *fontFileStream = NULL; + auto it = m_fontDatas.constFind(key); + if (it == m_fontDatas.constEnd()) + return E_FAIL; + + QByteArray fontData = it.value(); + DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); + stream->AddRef(); + *fontFileStream = stream; + + return S_OK; + } + + class CustomFontFileLoader + { + public: + CustomFontFileLoader(IDWriteFactory *factory) + { + m_directWriteFactory = factory; + + if (m_directWriteFactory) { + m_directWriteFactory->AddRef(); + + m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); + m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); + } + } + + ~CustomFontFileLoader() + { + if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr) + m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader); + + if (m_directWriteFactory != nullptr) + m_directWriteFactory->Release(); + } + + void addKey(const void *key, const QByteArray &fontData) + { + if (m_directWriteFontFileLoader != nullptr) + m_directWriteFontFileLoader->addKey(key, fontData); + } + + void removeKey(const void *key) + { + if (m_directWriteFontFileLoader != nullptr) + m_directWriteFontFileLoader->removeKey(key); + } + + IDWriteFontFileLoader *loader() const + { + return m_directWriteFontFileLoader; + } + + private: + IDWriteFactory *m_directWriteFactory = nullptr; + DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr; + }; +} // Anonymous namespace + +#endif // directwrite && direct2d + + +QWindowsFontEngineData::~QWindowsFontEngineData() +{ + if (hdc) + DeleteDC(hdc); + +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) + if (directWriteGdiInterop) + directWriteGdiInterop->Release(); + if (directWriteFactory) + directWriteFactory->Release(); +#endif +} + +QWindowsFontDatabaseBase::QWindowsFontDatabaseBase() +{ +} + +QWindowsFontDatabaseBase::~QWindowsFontDatabaseBase() +{ +} + +typedef QSharedPointer QWindowsFontEngineDataPtr; +typedef QThreadStorage FontEngineThreadLocalData; +Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData) + +QSharedPointer QWindowsFontDatabaseBase::data() +{ + FontEngineThreadLocalData *data = fontEngineThreadLocalData(); + if (!data->hasLocalData()) + data->setLocalData(QSharedPointer::create()); + + if (!init(data->localData())) + qCWarning(lcQpaFonts) << "Cannot initialize common font database data"; + + return data->localData(); +} + +bool QWindowsFontDatabaseBase::init(QSharedPointer d) +{ +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) + if (!d->directWriteFactory) { + createDirectWriteFactory(&d->directWriteFactory); + if (!d->directWriteFactory) + return false; + } + if (!d->directWriteGdiInterop) { + const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__); + return false; + } + } +#endif // directwrite && direct2d + return true; +} + +#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(result); +} + +void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory) +{ + *factory = nullptr; + + static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory(); + if (!dWriteCreateFactory) + return; + + IUnknown *result = nullptr; +# if defined(QT_USE_DIRECTWRITE3) + dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); +# endif + +# if defined(QT_USE_DIRECTWRITE2) + if (result == nullptr) + dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); +# endif + + if (result == nullptr) { + if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { + qErrnoWarning("DWriteCreateFactory failed"); + return; + } + } + + *factory = static_cast(result); +} +#endif // directwrite && direct2d + +static int s_defaultVerticalDPI = 96; // Native Pixels + +int QWindowsFontDatabaseBase::defaultVerticalDPI() +{ + return s_defaultVerticalDPI; +} + +void QWindowsFontDatabaseBase::setDefaultVerticalDPI(int d) +{ + s_defaultVerticalDPI = d; +} + +LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName) +{ + LOGFONT lf; + memset(&lf, 0, sizeof(LOGFONT)); + + lf.lfHeight = -qRound(request.pixelSize); + lf.lfWidth = 0; + lf.lfEscapement = 0; + lf.lfOrientation = 0; + if (request.weight == 50) + lf.lfWeight = FW_DONTCARE; + else + lf.lfWeight = (request.weight*900)/99; + lf.lfItalic = request.style != QFont::StyleNormal; + lf.lfCharSet = DEFAULT_CHARSET; + + int strat = OUT_DEFAULT_PRECIS; + if (request.styleStrategy & QFont::PreferBitmap) { + strat = OUT_RASTER_PRECIS; + } else if (request.styleStrategy & QFont::PreferDevice) { + strat = OUT_DEVICE_PRECIS; + } else if (request.styleStrategy & QFont::PreferOutline) { + strat = OUT_OUTLINE_PRECIS; + } else if (request.styleStrategy & QFont::ForceOutline) { + strat = OUT_TT_ONLY_PRECIS; + } + + lf.lfOutPrecision = strat; + + int qual = DEFAULT_QUALITY; + + if (request.styleStrategy & QFont::PreferMatch) + qual = DRAFT_QUALITY; + else if (request.styleStrategy & QFont::PreferQuality) + qual = PROOF_QUALITY; + + if (request.styleStrategy & QFont::PreferAntialias) { + qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0 + ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY; + } else if (request.styleStrategy & QFont::NoAntialias) { + qual = NONANTIALIASED_QUALITY; + } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) { + qual = ANTIALIASED_QUALITY; + } + + lf.lfQuality = qual; + + lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; + + int hint = FF_DONTCARE; + switch (request.styleHint) { + case QFont::Helvetica: + hint = FF_SWISS; + break; + case QFont::Times: + hint = FF_ROMAN; + break; + case QFont::Courier: + hint = FF_MODERN; + break; + case QFont::OldEnglish: + hint = FF_DECORATIVE; + break; + case QFont::System: + hint = FF_MODERN; + break; + default: + break; + } + + lf.lfPitchAndFamily = DEFAULT_PITCH | hint; + + QString fam = faceName; + if (fam.isEmpty()) + fam = request.families.size() > 0 ? request.families.at(0) : request.family; + if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) { + qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam)); + 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; +} + +QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) +{ + if (verticalDPI_In <= 0) + verticalDPI_In = defaultVerticalDPI(); + QFont qFont(QString::fromWCharArray(logFont.lfFaceName)); + qFont.setItalic(logFont.lfItalic); + if (logFont.lfWeight != FW_DONTCARE) + qFont.setWeight(QPlatformFontDatabase::weightFromInteger(logFont.lfWeight)); + const qreal logFontHeight = qAbs(logFont.lfHeight); + qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); + qFont.setUnderline(logFont.lfUnderline); + qFont.setOverline(false); + qFont.setStrikeOut(logFont.lfStrikeOut); + return qFont; +} + +// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont() +HFONT QWindowsFontDatabaseBase::systemFont() +{ + static const auto stock_sysfont = + reinterpret_cast(GetStockObject(DEFAULT_GUI_FONT)); + return stock_sysfont; +} + +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); + const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); + qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; + return systemFont; +} + +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) +IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const +{ + QSharedPointer fontEngineData = data(); + if (fontEngineData->directWriteFactory == nullptr) { + qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()"; + return nullptr; + } + + CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory); + fontFileLoader.addKey(this, fontData); + + IDWriteFontFile *fontFile = nullptr; + const void *key = this; + + HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key, + sizeof(void *), + fontFileLoader.loader(), + &fontFile); + if (FAILED(hres)) { + qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__); + return nullptr; + } + + BOOL isSupportedFontType; + DWRITE_FONT_FILE_TYPE fontFileType; + DWRITE_FONT_FACE_TYPE fontFaceType; + UINT32 numberOfFaces; + fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); + if (!isSupportedFontType) { + fontFile->Release(); + return nullptr; + } + + // ### 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; + } + + fontFile->Release(); + return directWriteFontFace; +} +#endif // directwrite && direct2d + +QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) +{ + QFontEngine *fontEngine = nullptr; + +#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d) + QSharedPointer fontEngineData = data(); + if (fontEngineData->directWriteFactory == nullptr) + return nullptr; + + IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData); + fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, + pixelSize, + fontEngineData); + + // Get font family from font data + EmbeddedFont font(fontData); + font.updateFromOS2Table(fontEngine); + fontEngine->fontDef.family = font.familyName(); + fontEngine->fontDef.hintingPreference = hintingPreference; + + directWriteFontFace->Release(); +#else // directwrite && direct2d + Q_UNUSED(fontData); + Q_UNUSED(pixelSize); + Q_UNUSED(hintingPreference); +#endif + + return fontEngine; +} + +QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint) +{ + switch (styleHint) { + case QFont::Times: + return QStringLiteral("Times New Roman"); + case QFont::Courier: + return QStringLiteral("Courier New"); + case QFont::Monospace: + return QStringLiteral("Courier New"); + case QFont::Cursive: + return QStringLiteral("Comic Sans MS"); + case QFont::Fantasy: + return QStringLiteral("Impact"); + case QFont::Decorative: + return QStringLiteral("Old English"); + case QFont::Helvetica: + return QStringLiteral("Arial"); + case QFont::System: + default: + break; + } + return QStringLiteral("MS Shell Dlg 2"); +} + +// Creation functions + +static const char *other_tryFonts[] = { + "Arial", + "MS UI Gothic", + "Gulim", + "SimSun", + "PMingLiU", + "Arial Unicode MS", + 0 +}; + +static const char *jp_tryFonts [] = { + "MS UI Gothic", + "Arial", + "Gulim", + "SimSun", + "PMingLiU", + "Arial Unicode MS", + 0 +}; + +static const char *ch_CN_tryFonts [] = { + "SimSun", + "Arial", + "PMingLiU", + "Gulim", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char *ch_TW_tryFonts [] = { + "PMingLiU", + "Arial", + "SimSun", + "Gulim", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char *kr_tryFonts[] = { + "Gulim", + "Arial", + "PMingLiU", + "SimSun", + "MS UI Gothic", + "Arial Unicode MS", + 0 +}; + +static const char **tryFonts = nullptr; + +QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &family) +{ + QStringList result; + QFontDatabase db; + if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) { + if (!tryFonts) { + LANGID lid = GetUserDefaultLangID(); + switch (lid&0xff) { + case LANG_CHINESE: // Chinese + if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore + tryFonts = ch_CN_tryFonts; + else + tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau + break; + case LANG_JAPANESE: + tryFonts = jp_tryFonts; + break; + case LANG_KOREAN: + tryFonts = kr_tryFonts; + break; + default: + tryFonts = other_tryFonts; + break; + } + } + QFontDatabase db; + const QStringList families = db.families(); + const char **tf = tryFonts; + while (tf && *tf) { + // QTBUG-31689, family might be an English alias for a localized font name. + const QString family = QString::fromLatin1(*tf); + if (families.contains(family) || db.hasFamily(family)) + result << family; + ++tf; + } + } + result.append(QStringLiteral("Segoe UI Emoji")); + result.append(QStringLiteral("Segoe UI Symbol")); + return result; +} + +QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsfontdatabasebase_p.h b/src/gui/text/windows/qwindowsfontdatabasebase_p.h new file mode 100644 index 0000000000..7f712a2323 --- /dev/null +++ b/src/gui/text/windows/qwindowsfontdatabasebase_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTDATABASEBASE_P_H +#define QWINDOWSFONTDATABASEBASE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +#if !defined(QT_NO_DIRECTWRITE) + struct IDWriteFactory; + struct IDWriteGdiInterop; + struct IDWriteFontFace; +#endif + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts); + +class QWindowsFontEngineData +{ + Q_DISABLE_COPY_MOVE(QWindowsFontEngineData) +public: + QWindowsFontEngineData(); + ~QWindowsFontEngineData(); + + uint pow_gamma[256]; + + bool clearTypeEnabled = false; + qreal fontSmoothingGamma; + HDC hdc = 0; +#if !defined(QT_NO_DIRECTWRITE) + IDWriteFactory *directWriteFactory = nullptr; + IDWriteGdiInterop *directWriteGdiInterop = nullptr; +#endif +}; + +class Q_GUI_EXPORT QWindowsFontDatabaseBase : public QPlatformFontDatabase +{ +public: + QWindowsFontDatabaseBase(); + ~QWindowsFontDatabaseBase() override; + + QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; + + static int defaultVerticalDPI(); + static void setDefaultVerticalDPI(int d); + + static QSharedPointer data(); +#if !defined(QT_NO_DIRECTWRITE) + static void createDirectWriteFactory(IDWriteFactory **factory); +#endif + static QFont systemDefaultFont(); + static HFONT systemFont(); + static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName); + static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0); + + static QString familyForStyleHint(QFont::StyleHint styleHint); + static QStringList extraTryFontsForFamily(const QString &family); + + class FontTable{}; + class EmbeddedFont + { + public: + EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) {} + + QString changeFamilyName(const QString &newFamilyName); + QByteArray data() const { return m_fontData; } + void updateFromOS2Table(QFontEngine *fontEngine); + FontTable *tableDirectoryEntry(const QByteArray &tagName); + QString familyName(FontTable *nameTableDirectory = nullptr); + + private: + QByteArray m_fontData; + }; + +protected: + +#if !defined(QT_NO_DIRECTWRITE) + IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData) const; +#endif + +private: + static bool init(QSharedPointer data); +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSFONTDATABASEBASE_P_H diff --git a/src/gui/text/windows/qwindowsfontengine.cpp b/src/gui/text/windows/qwindowsfontengine.cpp new file mode 100644 index 0000000000..6248041a3d --- /dev/null +++ b/src/gui/text/windows/qwindowsfontengine.cpp @@ -0,0 +1,1204 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module 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$ +** +****************************************************************************/ + +#include "qwindowsfontengine_p.h" +#include "qwindowsnativeimage_p.h" +#include "qwindowsfontdatabase_p.h" +#include +#include "qwindowsfontenginedirectwrite_p.h" + +#include +#include // glyph_metrics_t +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#if !defined(QT_NO_DIRECTWRITE) +# include +# include +#endif + +QT_BEGIN_NAMESPACE + +//### mingw needed define +#ifndef TT_PRIM_CSPLINE +#define TT_PRIM_CSPLINE 3 +#endif + +// GetFontData expects the tags in little endian ;( +#define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4) (\ + (((quint32)(ch4)) << 24) | \ + (((quint32)(ch3)) << 16) | \ + (((quint32)(ch2)) << 8) | \ + ((quint32)(ch1)) \ + ) + +// common DC for all fonts + +typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT); +static PtrGetCharWidthI ptrGetCharWidthI = 0; +static bool resolvedGetCharWidthI = false; + +static void resolveGetCharWidthI() +{ + if (resolvedGetCharWidthI) + return; + resolvedGetCharWidthI = true; + ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI"); +} + +// general font engine + +QFixed QWindowsFontEngine::lineThickness() const +{ + if(lineWidth > 0) + return lineWidth; + + return QFontEngine::lineThickness(); +} + +static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc) +{ + const auto size = GetOutlineTextMetrics(hdc, 0, nullptr); + auto otm = reinterpret_cast(malloc(size)); + GetOutlineTextMetrics(hdc, size, otm); + return otm; +} + +bool QWindowsFontEngine::hasCFFTable() const +{ + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR; +} + +bool QWindowsFontEngine::hasCMapTable() const +{ + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('c', 'm', 'a', 'p'), 0, 0, 0) != GDI_ERROR; +} + +static inline QString stringFromOutLineTextMetric(const OUTLINETEXTMETRIC *otm, PSTR offset) +{ + const uchar *p = reinterpret_cast(otm) + quintptr(offset); + return QString::fromWCharArray(reinterpret_cast(p)); +} + +void QWindowsFontEngine::getCMap() +{ + ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable(); + + cffTable = hasCFFTable(); + + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + bool symb = false; + if (ttf) { + cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); + cmap = QFontEngine::getCMap(reinterpret_cast(cmapTable.constData()), + cmapTable.size(), &symb, &cmapSize); + } + if (!cmap) { + ttf = false; + symb = false; + } + symbol = symb; + designToDevice = 1; + _faceId.index = 0; + if(cmap) { + OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); + unitsPerEm = int(otm->otmEMSquare); + const QFixed unitsPerEmF(unitsPerEm); + designToDevice = unitsPerEmF / QFixed::fromReal(fontDef.pixelSize); + x_height = int(otm->otmsXHeight); + loadKerningPairs(designToDevice); + _faceId.filename = QFile::encodeName(stringFromOutLineTextMetric(otm, otm->otmpFullName)); + lineWidth = otm->otmsUnderscoreSize; + fsType = otm->otmfsType; + free(otm); + + } else { + unitsPerEm = tm.tmHeight; + } +} + +int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const +{ + int glyph_pos = 0; + { + if (symbol) { + QStringIterator it(str, str + numChars); + while (it.hasNext()) { + const uint uc = it.next(); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); + if(!glyphs->glyphs[glyph_pos] && uc < 0x100) + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); + ++glyph_pos; + } + } else if (ttf) { + QStringIterator it(str, str + numChars); + while (it.hasNext()) { + const uint uc = it.next(); + glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); + ++glyph_pos; + } + } else { + QStringIterator it(str, str + numChars); + while (it.hasNext()) { + const uint uc = it.next(); + if (uc >= tm.tmFirstChar && uc <= tm.tmLastChar) + glyphs->glyphs[glyph_pos] = uc; + else + glyphs->glyphs[glyph_pos] = 0; + ++glyph_pos; + } + } + } + glyphs->numGlyphs = glyph_pos; + return glyph_pos; +} + +/*! + \class QWindowsFontEngine + \brief Standard Windows font engine. + \internal + + Will probably be superseded by a common Free Type font engine in Qt 5.X. +*/ + +QWindowsFontEngine::QWindowsFontEngine(const QString &name, + LOGFONT lf, + const QSharedPointer &fontEngineData) + : QFontEngine(Win), + m_fontEngineData(fontEngineData), + _name(name), + m_logfont(lf), + ttf(0), + hasOutline(0) +{ + qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight; + hfont = CreateFontIndirect(&m_logfont); + if (!hfont) { + qErrnoWarning("%s: CreateFontIndirect failed for family '%s'", __FUNCTION__, qPrintable(name)); + hfont = QWindowsFontDatabase::systemFont(); + } + + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + const BOOL res = GetTextMetrics(hdc, &tm); + if (!res) { + qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__); + ZeroMemory(&tm, sizeof(TEXTMETRIC)); + } + + fontDef.pixelSize = -lf.lfHeight; + fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); + + cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000; + getCMap(); + + if (!resolvedGetCharWidthI) + resolveGetCharWidthI(); + + // ### Properties accessed by QWin32PrintEngine (QtPrintSupport) + QVariantMap userData; + userData.insert(QStringLiteral("logFont"), QVariant::fromValue(m_logfont)); + userData.insert(QStringLiteral("hFont"), QVariant::fromValue(hfont)); + userData.insert(QStringLiteral("trueType"), QVariant(bool(ttf))); + setUserData(userData); + + hasUnreliableOutline = (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) == 0; +} + +QWindowsFontEngine::~QWindowsFontEngine() +{ + if (designAdvances) + free(designAdvances); + + if (widthCache) + free(widthCache); + + // make sure we aren't by accident still selected + SelectObject(m_fontEngineData->hdc, QWindowsFontDatabase::systemFont()); + + if (!DeleteObject(hfont)) + qErrnoWarning("%s: QFontEngineWin: failed to delete font...", __FUNCTION__); + qCDebug(lcQpaFonts) << __FUNCTION__ << _name; + + if (!uniqueFamilyName.isEmpty()) { + if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) { + QPlatformFontDatabase *pfdb = pi->fontDatabase(); + static_cast(pfdb)->derefUniqueFont(uniqueFamilyName); + } + } +} + +glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const +{ + glyph_t glyph = 0; + + if (symbol) { + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); + if (glyph == 0 && ucs4 < 0x100) + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); + } else if (ttf) { + glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); + } else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) { + glyph = ucs4; + } + + return glyph; +} + +HGDIOBJ QWindowsFontEngine::selectDesignFont() const +{ + LOGFONT f = m_logfont; + f.lfHeight = -unitsPerEm; + f.lfWidth = 0; + HFONT designFont = CreateFontIndirect(&f); + return SelectObject(m_fontEngineData->hdc, designFont); +} + +bool QWindowsFontEngine::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; + } + + glyphs->numGlyphs = *nglyphs; + *nglyphs = getGlyphIndexes(str, len, glyphs); + + if (!(flags & GlyphIndicesOnly)) + recalcAdvances(glyphs, flags); + + return true; +} + +inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width) +{ + if (ptrGetCharWidthI) + ptrGetCharWidthI(hdc, glyph, 1, 0, &width); +} + +void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const +{ + HGDIOBJ oldFont = 0; + HDC hdc = m_fontEngineData->hdc; + if (ttf && (flags & DesignMetrics)) { + for(int i = 0; i < glyphs->numGlyphs; i++) { + unsigned int glyph = glyphs->glyphs[i]; + if(int(glyph) >= designAdvancesSize) { + const int newSize = int(glyph + 256) >> 8 << 8; + designAdvances = reinterpret_cast(realloc(designAdvances, size_t(newSize) * sizeof(QFixed))); + Q_CHECK_PTR(designAdvances); + for(int i = designAdvancesSize; i < newSize; ++i) + designAdvances[i] = -1000000; + designAdvancesSize = newSize; + } + if (designAdvances[glyph] < -999999) { + if (!oldFont) + oldFont = selectDesignFont(); + + int width = 0; + calculateTTFGlyphWidth(hdc, glyph, width); + designAdvances[glyph] = QFixed(width) / designToDevice; + } + glyphs->advances[i] = designAdvances[glyph]; + } + if(oldFont) + DeleteObject(SelectObject(hdc, oldFont)); + } else { + for(int i = 0; i < glyphs->numGlyphs; i++) { + unsigned int glyph = glyphs->glyphs[i]; + + if (glyph >= widthCacheSize) { + const uint newSize = (glyph + 256) >> 8 << 8; + widthCache = reinterpret_cast(realloc(widthCache, newSize * sizeof(QFixed))); + Q_CHECK_PTR(widthCache); + memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize); + widthCacheSize = newSize; + } + glyphs->advances[i] = widthCache[glyph]; + // font-width cache failed + if (glyphs->advances[i].value() == 0) { + int width = 0; + if (!oldFont) + oldFont = SelectObject(hdc, hfont); + + if (!ttf) { + QChar ch[2] = { ushort(glyph), 0 }; + int chrLen = 1; + if (QChar::requiresSurrogates(glyph)) { + ch[0] = QChar::highSurrogate(glyph); + ch[1] = QChar::lowSurrogate(glyph); + ++chrLen; + } + SIZE size = {0, 0}; + GetTextExtentPoint32(hdc, reinterpret_cast(ch), chrLen, &size); + width = size.cx; + } else { + calculateTTFGlyphWidth(hdc, glyph, width); + } + glyphs->advances[i] = width; + // if glyph's within cache range, store it for later + if (width > 0 && width < 0x100) + widthCache[glyph] = uchar(width); + } + } + + if (oldFont) + SelectObject(hdc, oldFont); + } +} + +glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs) +{ + if (glyphs.numGlyphs == 0) + return glyph_metrics_t(); + + QFixed w = 0; + for (int i = 0; i < glyphs.numGlyphs; ++i) + w += glyphs.effectiveAdvance(i); + + return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0); +} + +bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const +{ + Q_ASSERT(metrics != 0); + + HDC hdc = m_fontEngineData->hdc; + + GLYPHMETRICS gm; + DWORD res = 0; + MAT2 mat; + mat.eM11.value = mat.eM22.value = 1; + mat.eM11.fract = mat.eM22.fract = 0; + mat.eM21.value = mat.eM12.value = 0; + mat.eM21.fract = mat.eM12.fract = 0; + + if (t.type() > QTransform::TxTranslate) { + // We need to set the transform using the HDC's world + // matrix rather than using the MAT2 above, because the + // results provided when transforming via MAT2 does not + // match the glyphs that are drawn using a WorldTransform + XFORM xform; + xform.eM11 = FLOAT(t.m11()); + xform.eM12 = FLOAT(t.m12()); + xform.eM21 = FLOAT(t.m21()); + xform.eM22 = FLOAT(t.m22()); + xform.eDx = 0; + xform.eDy = 0; + SetGraphicsMode(hdc, GM_ADVANCED); + SetWorldTransform(hdc, &xform); + } + + uint format = GGO_METRICS; + if (ttf) + format |= GGO_GLYPH_INDEX; + res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat); + + if (t.type() > QTransform::TxTranslate) { + XFORM xform; + xform.eM11 = xform.eM22 = 1; + xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0; + SetWorldTransform(hdc, &xform); + SetGraphicsMode(hdc, GM_COMPATIBLE); + } + + if (res != GDI_ERROR) { + *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y, + int(gm.gmBlackBoxX), int(gm.gmBlackBoxY), + gm.gmCellIncX, gm.gmCellIncY); + return true; + } else { + return false; + } +} + +glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t) +{ + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + + glyph_metrics_t glyphMetrics; + bool success = getOutlineMetrics(glyph, t, &glyphMetrics); + + if (!ttf && !success) { + // Bitmap fonts + wchar_t ch = wchar_t(glyph); + ABCFLOAT abc; + GetCharABCWidthsFloat(hdc, ch, ch, &abc); + int width = qRound(abc.abcfB); + + return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t); + } + + return glyphMetrics; +} + +namespace { +# pragma pack(1) + + struct OS2Table + { + quint16 version; + qint16 avgCharWidth; + quint16 weightClass; + quint16 widthClass; + quint16 type; + qint16 subscriptXSize; + qint16 subscriptYSize; + qint16 subscriptXOffset; + qint16 subscriptYOffset; + qint16 superscriptXSize; + qint16 superscriptYSize; + qint16 superscriptXOffset; + qint16 superscriptYOffset; + qint16 strikeOutSize; + qint16 strikeOutPosition; + qint16 familyClass; + quint8 panose[10]; + quint32 unicodeRanges[4]; + quint8 vendorID[4]; + quint16 selection; + quint16 firstCharIndex; + quint16 lastCharIndex; + qint16 typoAscender; + qint16 typoDescender; + qint16 typoLineGap; + quint16 winAscent; + quint16 winDescent; + quint32 codepageRanges[2]; + qint16 height; + qint16 capHeight; + quint16 defaultChar; + quint16 breakChar; + quint16 maxContext; + }; + +# pragma pack() +} + +QFixed QWindowsFontEngine::capHeight() const +{ + const QByteArray tableData = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); + if (size_t(tableData.size()) >= sizeof(OS2Table)) { + const OS2Table *table = reinterpret_cast(tableData.constData()); + if (qFromBigEndian(table->version) >= 2) { + qint16 capHeight = qFromBigEndian(table->capHeight); + if (capHeight > 0) + return QFixed(capHeight) / designToDevice; + } + } + return calculatedCapHeight(); +} + +QFixed QWindowsFontEngine::xHeight() const +{ + if(x_height >= 0) + return x_height; + return QFontEngine::xHeight(); +} + +QFixed QWindowsFontEngine::averageCharWidth() const +{ + return tm.tmAveCharWidth; +} + +qreal QWindowsFontEngine::maxCharWidth() const +{ + return tm.tmMaxCharWidth; +} + +enum { max_font_count = 256 }; +static const ushort char_table[] = { + 40, + 67, + 70, + 75, + 86, + 88, + 89, + 91, + 102, + 114, + 124, + 127, + 205, + 645, + 884, + 922, + 1070, + 12386, + 0 +}; + +static const int char_table_entries = sizeof(char_table)/sizeof(ushort); + +#ifndef Q_CC_MINGW +void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing) +{ + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + + if (ttf) { + ABC abcWidths; + GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths); + if (leftBearing) + *leftBearing = abcWidths.abcA; + if (rightBearing) + *rightBearing = abcWidths.abcC; + } else { + QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing); + } +} +#endif // Q_CC_MINGW + +void QWindowsFontEngine::initializeHeightMetrics() const +{ + m_ascent = tm.tmAscent; + m_descent = tm.tmDescent; + m_leading = tm.tmExternalLeading; + + QFontEngine::initializeHeightMetrics(); +} + +bool QWindowsFontEngine::hasUnreliableGlyphOutline() const +{ + return hasUnreliableOutline || QFontEngine::hasUnreliableGlyphOutline(); +} + +qreal QWindowsFontEngine::minLeftBearing() const +{ + if (lbearing == SHRT_MIN) + minRightBearing(); // calculates both + + return lbearing; +} + +qreal QWindowsFontEngine::minRightBearing() const +{ + if (rbearing == SHRT_MIN) { + int ml = 0; + int mr = 0; + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + if (ttf) { + ABC *abc = 0; + int n = tm.tmLastChar - tm.tmFirstChar; + if (n <= max_font_count) { + abc = new ABC[n+1]; + GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc); + } else { + abc = new ABC[char_table_entries+1]; + for(int i = 0; i < char_table_entries; i++) + GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i); + n = char_table_entries; + } + ml = abc[0].abcA; + mr = abc[0].abcC; + for (int i = 1; i < n; i++) { + if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) { + ml = qMin(ml,abc[i].abcA); + mr = qMin(mr,abc[i].abcC); + } + } + delete [] abc; + } else { + ABCFLOAT *abc = 0; + int n = tm.tmLastChar - tm.tmFirstChar+1; + if (n <= max_font_count) { + abc = new ABCFLOAT[n]; + GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc); + } else { + abc = new ABCFLOAT[char_table_entries]; + for(int i = 0; i < char_table_entries; i++) + GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i); + n = char_table_entries; + } + float fml = abc[0].abcfA; + float fmr = abc[0].abcfC; + for (int i=1; i(dataBuffer + headerOffset); + + QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch)); + path->moveTo(lastPoint + oset); + offset += sizeof(TTPOLYGONHEADER); + while (offset < headerOffset + ttph->cb) { + const TTPOLYCURVE *curve = reinterpret_cast(dataBuffer + offset); + switch (curve->wType) { + case TT_PRIM_LINE: { + for (int i=0; icpfx; ++i) { + QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; + path->lineTo(p); + } + break; + } + case TT_PRIM_QSPLINE: { + const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1); + QPointF prev(elm.x, elm.y); + QPointF endPoint; + for (int i=0; icpfx - 1; ++i) { + QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; + QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset; + if (i < curve->cpfx - 2) { + endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2); + } else { + endPoint = p2; + } + + path->quadTo(p1, endPoint); + prev = endPoint; + } + + break; + } + case TT_PRIM_CSPLINE: { + for (int i=0; icpfx; ) { + QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; + QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; + QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; + path->cubicTo(p2, p3, p4); + } + break; + } + default: + qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case"); + } + offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX); + } + path->closeSubpath(); + headerOffset += ttph->cb; + } + delete [] dataBuffer; + + return true; +} + +void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags) +{ + LOGFONT lf = m_logfont; + // The sign must be negative here to make sure we match against character height instead of + // hinted cell height. This ensures that we get linear matching, and we need this for + // paths since we later on apply a scaling transform to the glyph outline to get the + // font at the correct pixel size. + lf.lfHeight = -unitsPerEm; + lf.lfWidth = 0; + HFONT hf = CreateFontIndirect(&lf); + HDC hdc = m_fontEngineData->hdc; + HGDIOBJ oldfont = SelectObject(hdc, hf); + + qreal scale = qreal(fontDef.pixelSize) / unitsPerEm; + qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0; + for(int i = 0; i < nglyphs; ++i) { + if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0, + scale, stretch)) { + // Some windows fonts, like "Modern", are vector stroke + // fonts, which are reported as TMPF_VECTOR but do not + // support GetGlyphOutline, and thus we set this bit so + // that addOutLineToPath can check it and return safely... + hasOutline = false; + break; + } + } + DeleteObject(SelectObject(hdc, oldfont)); +} + +void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, + QPainterPath *path, QTextItem::RenderFlags flags) +{ + if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) { + hasOutline = true; + QFontEngine::addOutlineToPath(x, y, glyphs, path, flags); + if (hasOutline) { + // has_outline is set to false if addGlyphToPath gets + // false from GetGlyphOutline, meaning its not an outline + // font. + return; + } + } + QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags); +} + +QFontEngine::FaceId QWindowsFontEngine::faceId() const +{ + return _faceId; +} + +QT_BEGIN_INCLUDE_NAMESPACE +#include +QT_END_INCLUDE_NAMESPACE + +int QWindowsFontEngine::synthesized() const +{ + if(synthesized_flags == -1) { + synthesized_flags = 0; + if(ttf) { + const DWORD HEAD = MAKE_LITTLE_ENDIAN_TAG('h', 'e', 'a', 'd'); + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + uchar data[4]; + GetFontData(hdc, HEAD, 44, &data, 4); + USHORT macStyle = qt_getUShort(data); + if (tm.tmItalic && !(macStyle & 2)) + synthesized_flags = SynthesizedItalic; + if (fontDef.stretch != 100 && ttf) + synthesized_flags |= SynthesizedStretch; + if (tm.tmWeight >= 500 && tm.tmWeight < 750 && !(macStyle & 1)) + synthesized_flags |= SynthesizedBold; + //qDebug() << "font is" << _name << + // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags; + } + } + return synthesized_flags; +} + +QFixed QWindowsFontEngine::emSquareSize() const +{ + return unitsPerEm; +} + +QFontEngine::Properties QWindowsFontEngine::properties() const +{ + LOGFONT lf = m_logfont; + lf.lfHeight = unitsPerEm; + HFONT hf = CreateFontIndirect(&lf); + HDC hdc = m_fontEngineData->hdc; + HGDIOBJ oldfont = SelectObject(hdc, hf); + OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); + Properties p; + p.emSquare = unitsPerEm; + p.italicAngle = otm->otmItalicAngle; + const QByteArray name = stringFromOutLineTextMetric(otm, otm->otmpFamilyName).toLatin1() + + stringFromOutLineTextMetric(otm, otm->otmpStyleName).toLatin1(); + p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(name); + p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top, + otm->otmrcFontBox.right - otm->otmrcFontBox.left, + otm->otmrcFontBox.top - otm->otmrcFontBox.bottom); + p.ascent = otm->otmAscent; + p.descent = -otm->otmDescent; + p.leading = int(otm->otmLineGap); + p.capHeight = 0; + p.lineWidth = otm->otmsUnderscoreSize; + free(otm); + DeleteObject(SelectObject(hdc, oldfont)); + return p; +} + +void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) +{ + LOGFONT lf = m_logfont; + lf.lfHeight = -unitsPerEm; + int flags = synthesized(); + if(flags & SynthesizedItalic) + lf.lfItalic = false; + lf.lfWidth = 0; + HFONT hf = CreateFontIndirect(&lf); + HDC hdc = m_fontEngineData->hdc; + HGDIOBJ oldfont = SelectObject(hdc, hf); + QFixedPoint p; + p.x = 0; + p.y = 0; + addGlyphToPath(glyph, p, hdc, path, ttf, metrics); + DeleteObject(SelectObject(hdc, oldfont)); +} + +bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + if (!ttf && !cffTable) + return false; + HDC hdc = m_fontEngineData->hdc; + SelectObject(hdc, hfont); + DWORD t = qbswap(tag); + *length = GetFontData(hdc, t, 0, buffer, *length); + Q_ASSERT(*length == GDI_ERROR || int(*length) > 0); + return *length != GDI_ERROR; +} + +#if !defined(CLEARTYPE_QUALITY) +# define CLEARTYPE_QUALITY 5 +#endif + +QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin, + const QTransform &t, + QImage::Format mask_format) +{ + Q_UNUSED(mask_format) + glyph_metrics_t gm = boundingBox(glyph); + +// printf(" -> for glyph %4x\n", glyph); + + int gx = gm.x.toInt(); + int gy = gm.y.toInt(); + int iw = gm.width.toInt(); + int ih = gm.height.toInt(); + + if (iw <= 0 || ih <= 0) + return 0; + + bool has_transformation = t.type() > QTransform::TxTranslate; + + unsigned int options = ttf ? ETO_GLYPH_INDEX : 0; + XFORM xform; + + if (has_transformation) { + xform.eM11 = FLOAT(t.m11()); + xform.eM12 = FLOAT(t.m12()); + xform.eM21 = FLOAT(t.m21()); + xform.eM22 = FLOAT(t.m22()); + xform.eDx = margin; + xform.eDy = margin; + + const HDC hdc = m_fontEngineData->hdc; + + SetGraphicsMode(hdc, GM_ADVANCED); + SetWorldTransform(hdc, &xform); + HGDIOBJ old_font = SelectObject(hdc, font); + + const UINT ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0); + GLYPHMETRICS tgm; + MAT2 mat; + memset(&mat, 0, sizeof(mat)); + mat.eM11.value = mat.eM22.value = 1; + + const DWORD result = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat); + + XFORM identity = {1, 0, 0, 1, 0, 0}; + SetWorldTransform(hdc, &identity); + SetGraphicsMode(hdc, GM_COMPATIBLE); + SelectObject(hdc, old_font); + + if (result == GDI_ERROR) { + const int errorCode = int(GetLastError()); + qErrnoWarning(errorCode, "QWinFontEngine: unable to query transformed glyph metrics (GetGlyphOutline() failed, error %d)...", errorCode); + return 0; + } + + iw = int(tgm.gmBlackBoxX); + ih = int(tgm.gmBlackBoxY); + + xform.eDx -= tgm.gmptGlyphOrigin.x; + xform.eDy += tgm.gmptGlyphOrigin.y; + } + + // The padding here needs to be kept in sync with the values in alphaMapBoundingBox. + QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin, + ih + 2 * margin, + QWindowsNativeImage::systemFormat()); + + /*If cleartype is enabled we use the standard system format even on Windows CE + and not the special textbuffer format we have to use if cleartype is disabled*/ + + ni->image().fill(0xffffffff); + + HDC hdc = ni->hdc(); + + SelectObject(hdc, GetStockObject(NULL_BRUSH)); + SelectObject(hdc, GetStockObject(BLACK_PEN)); + SetTextColor(hdc, RGB(0,0,0)); + SetBkMode(hdc, TRANSPARENT); + SetTextAlign(hdc, TA_BASELINE); + + HGDIOBJ old_font = SelectObject(hdc, font); + + if (has_transformation) { + SetGraphicsMode(hdc, GM_ADVANCED); + SetWorldTransform(hdc, &xform); + ExtTextOut(hdc, 0, 0, options, 0, reinterpret_cast(&glyph), 1, 0); + } else { + ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, reinterpret_cast(&glyph), 1, 0); + } + + SelectObject(hdc, old_font); + return ni; +} + +glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat format) +{ + int margin = 0; + if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB) + margin = glyphMargin(QFontEngine::Format_A32); + glyph_metrics_t gm = boundingBox(glyph, matrix); + gm.width += margin * 2; + gm.height += margin * 2; + return gm; +} + +QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) +{ + HFONT font = hfont; + + bool clearTypeTemporarilyDisabled = (m_fontEngineData->clearTypeEnabled && m_logfont.lfQuality != NONANTIALIASED_QUALITY); + if (clearTypeTemporarilyDisabled) { + LOGFONT lf = m_logfont; + lf.lfQuality = ANTIALIASED_QUALITY; + font = CreateFontIndirect(&lf); + } + QImage::Format mask_format = QWindowsNativeImage::systemFormat(); + mask_format = QImage::Format_RGB32; + + const QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format); + if (mask == 0) { + if (m_fontEngineData->clearTypeEnabled) + DeleteObject(font); + return QImage(); + } + + QImage alphaMap(mask->width(), mask->height(), QImage::Format_Alpha8); + + + // Copy data... Cannot use QPainter here as GDI has messed up the + // Alpha channel of the ni.image pixels... + for (int y=0; yheight(); ++y) { + uchar *dest = alphaMap.scanLine(y); + if (mask->image().format() == QImage::Format_RGB16) { + const qint16 *src = reinterpret_cast(mask->image().constScanLine(y)); + for (int x=0; xwidth(); ++x) + dest[x] = 255 - qGray(src[x]); + } else { + const uint *src = reinterpret_cast(mask->image().constScanLine(y)); + for (int x=0; xwidth(); ++x) { + if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16) + dest[x] = 255 - qGray(src[x]); + else + dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.); + } + } + } + + // Cleanup... + delete mask; + if (clearTypeTemporarilyDisabled) { + DeleteObject(font); + } + + return alphaMap; +} + +#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C +#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D + +QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTransform &t) +{ + HFONT font = hfont; + + UINT contrast; + SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0); + SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast(quintptr(1000)), 0); + + int margin = glyphMargin(QFontEngine::Format_A32); + QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32); + SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast(quintptr(contrast)), 0); + + if (mask == 0) + return QImage(); + + // Gracefully handle the odd case when the display is 16-bit + const QImage source = mask->image().depth() == 32 + ? mask->image() + : mask->image().convertToFormat(QImage::Format_RGB32); + + QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32); + for (int y=0; yheight(); ++y) { + auto dest = reinterpret_cast(rgbMask.scanLine(y)); + const uint *src = reinterpret_cast(source.constScanLine(y)); + for (int x=0; xwidth(); ++x) { + dest[x] = 0xffffffff - (0x00ffffff & src[x]); + } + } + + delete mask; + + return rgbMask; +} + +QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const +{ + QFontDef request = fontDef; + QString actualFontName = request.family; + if (!uniqueFamilyName.isEmpty()) + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + const QString faceName = QString::fromWCharArray(m_logfont.lfFaceName); + + QFontEngine *fontEngine = + QWindowsFontDatabase::createEngine(request, faceName, + QWindowsFontDatabase::defaultVerticalDPI(), + m_fontEngineData); + if (fontEngine) { + fontEngine->fontDef.family = actualFontName; + if (!uniqueFamilyName.isEmpty()) { + static_cast(fontEngine)->setUniqueFamilyName(uniqueFamilyName); + if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) { + QPlatformFontDatabase *pfdb = pi->fontDatabase(); + static_cast(pfdb)->refUniqueFont(uniqueFamilyName); + } + } + } + return fontEngine; +} + +Qt::HANDLE QWindowsFontEngine::handle() const +{ + return hfont; +} + +void QWindowsFontEngine::initFontInfo(const QFontDef &request, + int dpi) +{ + fontDef = request; // most settings are equal + HDC dc = m_fontEngineData->hdc; + SelectObject(dc, hfont); + wchar_t n[64]; + GetTextFace(dc, 64, n); + fontDef.family = QString::fromWCharArray(n); + fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); + if (fontDef.pointSize < 0) { + fontDef.pointSize = fontDef.pixelSize * 72. / dpi; + } else if (fontDef.pixelSize == -1) { + fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); + } +} + +bool QWindowsFontEngine::supportsTransformation(const QTransform &transform) const +{ + // Support all transformations for ttf files, and translations for raster fonts + return ttf || transform.type() <= QTransform::TxTranslate; +} + +QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsfontengine_p.h b/src/gui/text/windows/qwindowsfontengine_p.h new file mode 100644 index 0000000000..8a676affcd --- /dev/null +++ b/src/gui/text/windows/qwindowsfontengine_p.h @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTENGINE_H +#define QWINDOWSFONTENGINE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QWindowsNativeImage; +class QWindowsFontEngineData; + +class QWindowsFontEngine : public QFontEngine +{ + Q_DISABLE_COPY_MOVE(QWindowsFontEngine) +public: + QWindowsFontEngine(const QString &name, LOGFONT lf, + const QSharedPointer &fontEngineData); + + ~QWindowsFontEngine() override; + void initFontInfo(const QFontDef &request, + int dpi); + + QFixed lineThickness() const override; + Properties properties() const override; + void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override; + FaceId faceId() const override; + bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; + int synthesized() const override; + 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; + void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; + + void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override; + void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags flags) override; + + HGDIOBJ selectDesignFont() const; + + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; + glyph_metrics_t boundingBox(glyph_t g) override { return boundingBox(g, QTransform()); } + glyph_metrics_t boundingBox(glyph_t g, const QTransform &t) override; + + + QFixed xHeight() const override; + QFixed capHeight() const override; + QFixed averageCharWidth() const override; + qreal maxCharWidth() const override; + qreal minLeftBearing() const override; + qreal minRightBearing() const override; + + QImage alphaMapForGlyph(glyph_t t) override { return alphaMapForGlyph(t, QTransform()); } + QImage alphaMapForGlyph(glyph_t, const QTransform &xform) override; + QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override; + glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) override; + + QFontEngine *cloneWithSize(qreal pixelSize) const override; + Qt::HANDLE handle() const override; + bool supportsTransformation(const QTransform &transform) const override; + +#ifndef Q_CC_MINGW + void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0) override; +#endif + + bool hasUnreliableGlyphOutline() const override; + + int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const; + void getCMap(); + + bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const; + + const QSharedPointer &fontEngineData() const { return m_fontEngineData; } + + void setUniqueFamilyName(const QString &newName) { uniqueFamilyName = newName; } + +protected: + void initializeHeightMetrics() const override; + +private: + QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform, + QImage::Format mask_format); + bool hasCFFTable() const; + bool hasCMapTable() const; + + const QSharedPointer m_fontEngineData; + + const QString _name; + QString uniqueFamilyName; + HFONT hfont = 0; + const LOGFONT m_logfont; + uint ttf : 1; + uint hasOutline : 1; + uint hasUnreliableOutline : 1; + uint cffTable : 1; + TEXTMETRIC tm; + const unsigned char *cmap = nullptr; + int cmapSize = 0; + QByteArray cmapTable; + mutable qreal lbearing = SHRT_MIN; + mutable qreal rbearing = SHRT_MIN; + QFixed designToDevice; + int unitsPerEm = 0; + QFixed x_height = -1; + FaceId _faceId; + + mutable int synthesized_flags = -1; + mutable QFixed lineWidth = -1; + mutable unsigned char *widthCache = nullptr; + mutable uint widthCacheSize = 0; + mutable QFixed *designAdvances = nullptr; + mutable int designAdvancesSize = 0; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(HFONT) +Q_DECLARE_METATYPE(LOGFONT) + +#endif // QWINDOWSFONTENGINE_H diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp new file mode 100644 index 0000000000..d96e65a532 --- /dev/null +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -0,0 +1,1030 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module 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$ +** +****************************************************************************/ + +#ifndef QT_NO_DIRECTWRITE + +#include "qwindowsfontenginedirectwrite_p.h" +#include "qwindowsfontdatabase_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(QT_USE_DIRECTWRITE2) +# include +#else +# include +#endif + +#include + +QT_BEGIN_NAMESPACE + +// Clang does not consider __declspec(nothrow) as nothrow +QT_WARNING_DISABLE_CLANG("-Wmicrosoft-exception-spec") + +// Convert from design units to logical pixels +#define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \ + QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize) + +namespace { + + class GeometrySink: public IDWriteGeometrySink + { + Q_DISABLE_COPY_MOVE(GeometrySink) + public: + GeometrySink(QPainterPath *path) + : m_refCount(0), m_path(path) + { + Q_ASSERT(m_path != 0); + } + virtual ~GeometrySink() = default; + + IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount); + IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount); + IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin); + IFACEMETHOD(Close)(); + IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd); + IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode); + IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags); + + IFACEMETHOD_(unsigned long, AddRef)(); + IFACEMETHOD_(unsigned long, Release)(); + IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject); + + private: + inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp) + { + return QPointF(inp.x, inp.y); + } + + unsigned long m_refCount; + QPointF m_startPoint; + QPainterPath *m_path; + }; + + void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, + UINT bezierCount) + { + for (uint i=0; icubicTo(c1, c2, p2); + } + } + + void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) + { + for (uint i=0; ilineTo(fromD2D1_POINT_2F(points[i])); + } + + void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint, + D2D1_FIGURE_BEGIN /*figureBegin*/) + { + m_startPoint = fromD2D1_POINT_2F(startPoint); + m_path->moveTo(m_startPoint); + } + + IFACEMETHODIMP GeometrySink::Close() + { + return E_NOTIMPL; + } + + void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) + { + if (figureEnd == D2D1_FIGURE_END_CLOSED) + m_path->closeSubpath(); + } + + void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) + { + m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE + ? Qt::OddEvenFill + : Qt::WindingFill); + } + + void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/) + { + /* Not implemented */ + } + + IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef() + { + return InterlockedIncrement(&m_refCount); + } + + IFACEMETHODIMP_(unsigned long) GeometrySink::Release() + { + unsigned long newCount = InterlockedDecrement(&m_refCount); + if (newCount == 0) + { + delete this; + return 0; + } + + return newCount; + } + + IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject) + { + if (__uuidof(IDWriteGeometrySink) == riid) { + *ppvObject = this; + } else if (__uuidof(IUnknown) == riid) { + *ppvObject = this; + } else { + *ppvObject = NULL; + return E_FAIL; + } + + AddRef(); + return S_OK; + } + +} + +static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE renderMode) +{ + switch (renderMode) { + case DWRITE_RENDERING_MODE_GDI_CLASSIC: + return DWRITE_MEASURING_MODE_GDI_CLASSIC; + case DWRITE_RENDERING_MODE_GDI_NATURAL: + return DWRITE_MEASURING_MODE_GDI_NATURAL; + default: + return DWRITE_MEASURING_MODE_NATURAL; + } +} + +static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPreference hintingPreference) +{ + if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting) + hintingPreference = QFont::PreferVerticalHinting; + + switch (hintingPreference) { + case QFont::PreferNoHinting: + return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; + case QFont::PreferVerticalHinting: + return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; + default: + return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; + } +} + +/*! + \class QWindowsFontEngineDirectWrite + \brief Windows font engine using Direct Write. + \internal + + Font engine for subpixel positioned text on Windows Vista + (with platform update) and later. If selected during + configuration, the engine will be selected only when the hinting + preference of a font is set to None or Vertical hinting, or + when fontengine=directwrite is selected as platform option. +*/ + +QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, + qreal pixelSize, + const QSharedPointer &d) + : QFontEngine(DirectWrite) + , m_fontEngineData(d) + , m_directWriteFontFace(directWriteFontFace) + , m_directWriteBitmapRenderTarget(0) + , m_lineThickness(-1) + , m_unitsPerEm(-1) + , m_capHeight(-1) + , m_xHeight(-1) +{ + qCDebug(lcQpaFonts) << __FUNCTION__ << pixelSize; + + Q_ASSERT(m_directWriteFontFace); + + m_fontEngineData->directWriteFactory->AddRef(); + m_directWriteFontFace->AddRef(); + + fontDef.pixelSize = pixelSize; + collectMetrics(); + cache_cost = (m_ascent.toInt() + m_descent.toInt()) * m_xHeight.toInt() * 2000; +} + +QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() +{ + qCDebug(lcQpaFonts) << __FUNCTION__; + + m_fontEngineData->directWriteFactory->Release(); + m_directWriteFontFace->Release(); + + if (m_directWriteBitmapRenderTarget != 0) + m_directWriteBitmapRenderTarget->Release(); + + if (!m_uniqueFamilyName.isEmpty()) { + QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); + static_cast(pfdb)->derefUniqueFont(m_uniqueFamilyName); + } +} + +#ifndef Q_CC_MINGW +typedef IDWriteLocalFontFileLoader QIdWriteLocalFontFileLoader; + +static UUID uuidIdWriteLocalFontFileLoader() +{ + return __uuidof(IDWriteLocalFontFileLoader); +} +#else // !Q_CC_MINGW +DECLARE_INTERFACE_(QIdWriteLocalFontFileLoader, IDWriteFontFileLoader) +{ + STDMETHOD(GetFilePathLengthFromKey)(THIS_ void const *, UINT32, UINT32*) PURE; + STDMETHOD(GetFilePathFromKey)(THIS_ void const *, UINT32, WCHAR *, UINT32) PURE; + STDMETHOD(GetLastWriteTimeFromKey)(THIS_ void const *, UINT32, FILETIME *) PURE; +}; + +static UUID uuidIdWriteLocalFontFileLoader() +{ + static const UUID result = { 0xb2d9f3ec, 0xc9fe, 0x4a11, {0xa2, 0xec, 0xd8, 0x62, 0x8, 0xf7, 0xc0, 0xa2}}; + return result; +} +#endif // Q_CC_MINGW + +QString QWindowsFontEngineDirectWrite::filenameFromFontFile(IDWriteFontFile *fontFile) +{ + IDWriteFontFileLoader *loader = nullptr; + + HRESULT hr = fontFile->GetLoader(&loader); + if (FAILED(hr)) { + qErrnoWarning("%s: GetLoader failed", __FUNCTION__); + return QString(); + } + + QIdWriteLocalFontFileLoader *localLoader = nullptr; + hr = loader->QueryInterface(uuidIdWriteLocalFontFileLoader(), + reinterpret_cast(&localLoader)); + + const void *fontFileReferenceKey = nullptr; + UINT32 fontFileReferenceKeySize = 0; + if (SUCCEEDED(hr)) { + hr = fontFile->GetReferenceKey(&fontFileReferenceKey, + &fontFileReferenceKeySize); + if (FAILED(hr)) + qErrnoWarning(hr, "%s: GetReferenceKey failed", __FUNCTION__); + } + + UINT32 filePathLength = 0; + if (SUCCEEDED(hr)) { + hr = localLoader->GetFilePathLengthFromKey(fontFileReferenceKey, + fontFileReferenceKeySize, + &filePathLength); + if (FAILED(hr)) + qErrnoWarning(hr, "GetFilePathLength failed", __FUNCTION__); + } + + QString ret; + if (SUCCEEDED(hr) && filePathLength > 0) { + QVarLengthArray filePath(filePathLength + 1); + + hr = localLoader->GetFilePathFromKey(fontFileReferenceKey, + fontFileReferenceKeySize, + filePath.data(), + filePathLength + 1); + if (FAILED(hr)) + qErrnoWarning(hr, "%s: GetFilePathFromKey failed", __FUNCTION__); + else + ret = QString::fromWCharArray(filePath.data()); + } + + if (localLoader != nullptr) + localLoader->Release(); + + if (loader != nullptr) + loader->Release(); + return ret; +} + +void QWindowsFontEngineDirectWrite::initializeHeightMetrics() const +{ + DWRITE_FONT_METRICS metrics; + m_directWriteFontFace->GetMetrics(&metrics); + + m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); + m_descent = DESIGN_TO_LOGICAL(metrics.descent); + m_leading = DESIGN_TO_LOGICAL(metrics.lineGap); + + QFontEngine::initializeHeightMetrics(); +} + +void QWindowsFontEngineDirectWrite::collectMetrics() +{ + DWRITE_FONT_METRICS metrics; + + m_directWriteFontFace->GetMetrics(&metrics); + m_unitsPerEm = metrics.designUnitsPerEm; + + m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); + m_capHeight = DESIGN_TO_LOGICAL(metrics.capHeight); + m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); + m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); + + IDWriteFontFile *fontFile = nullptr; + UINT32 numberOfFiles = 1; + if (SUCCEEDED(m_directWriteFontFace->GetFiles(&numberOfFiles, &fontFile))) { + m_faceId.filename = QFile::encodeName(filenameFromFontFile(fontFile)); + fontFile->Release(); + } + + QByteArray table = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a')); + const int advanceWidthMaxLocation = 10; + if (table.size() >= advanceWidthMaxLocation + int(sizeof(quint16))) { + quint16 advanceWidthMax = qFromBigEndian(table.constData() + advanceWidthMaxLocation); + m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax); + } +} + +QFixed QWindowsFontEngineDirectWrite::underlinePosition() const +{ + if (m_underlinePosition > 0) + return m_underlinePosition; + else + return QFontEngine::underlinePosition(); +} + +QFixed QWindowsFontEngineDirectWrite::lineThickness() const +{ + if (m_lineThickness > 0) + return m_lineThickness; + else + return QFontEngine::lineThickness(); +} + +bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + bool ret = false; + + const void *tableData = 0; + UINT32 tableSize; + void *tableContext = 0; + BOOL exists; + HRESULT hr = m_directWriteFontFace->TryGetFontTable(qbswap(tag), + &tableData, &tableSize, + &tableContext, &exists); + if (SUCCEEDED(hr)) { + if (exists) { + ret = true; + if (buffer && *length >= tableSize) + memcpy(buffer, tableData, tableSize); + *length = tableSize; + Q_ASSERT(int(*length) > 0); + } + m_directWriteFontFace->ReleaseFontTable(tableContext); + } else { + qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); + } + + return ret; +} + +QFixed QWindowsFontEngineDirectWrite::emSquareSize() const +{ + if (m_unitsPerEm > 0) + return m_unitsPerEm; + else + return QFontEngine::emSquareSize(); +} + +glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const +{ + UINT16 glyphIndex; + + HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(&ucs4, 1, &glyphIndex); + if (FAILED(hr)) { + qErrnoWarning("%s: glyphIndex failed", __FUNCTION__); + glyphIndex = 0; + } + + return glyphIndex; +} + +bool 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; + } + + QVarLengthArray codePoints(len); + int actualLength = 0; + QStringIterator it(str, str + len); + while (it.hasNext()) + codePoints[actualLength++] = it.next(); + + QVarLengthArray glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); + return false; + } + + for (int i = 0; i < actualLength; ++i) + glyphs->glyphs[i] = glyphIndices.at(i); + + *nglyphs = actualLength; + glyphs->numGlyphs = actualLength; + + if (!(flags & GlyphIndicesOnly)) + recalcAdvances(glyphs, {}); + + return true; +} + +QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const +{ + return m_faceId; +} + +void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const +{ + QVarLengthArray glyphIndices(glyphs->numGlyphs); + + // ### Caching? + for(int i=0; inumGlyphs; i++) + glyphIndices[i] = UINT16(glyphs->glyphs[i]); + + QVarLengthArray glyphMetrics(glyphIndices.size()); + + HRESULT hr; + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); + if (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL) { + hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize), + 1.0f, + NULL, + TRUE, + glyphIndices.data(), + glyphIndices.size(), + glyphMetrics.data()); + } else { + hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(), + glyphIndices.size(), + glyphMetrics.data()); + } + if (SUCCEEDED(hr)) { + qreal stretch = fontDef.stretch != QFont::AnyStretch ? fontDef.stretch / 100.0 : 1.0; + for (int i = 0; i < glyphs->numGlyphs; ++i) + glyphs->advances[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth * stretch); + } else { + qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); + } +} + +void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags flags) +{ + QVarLengthArray glyphIndices(nglyphs); + QVarLengthArray glyphOffsets(nglyphs); + QVarLengthArray glyphAdvances(nglyphs); + + for (int i=0; iGetGlyphRunOutline( + fontDef.pixelSize, + glyphIndices.data(), + glyphAdvances.data(), + glyphOffsets.data(), + nglyphs, + false, + flags & QTextItem::RightToLeft, + &geometrySink + ); + + if (FAILED(hr)) + qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__); +} + +glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs) +{ + if (glyphs.numGlyphs == 0) + return glyph_metrics_t(); + QFixed w = 0; + 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); +} + +glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) +{ + UINT16 glyphIndex = g; + + DWRITE_GLYPH_METRICS glyphMetrics; + HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics); + if (SUCCEEDED(hr)) { + QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth); + QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing); + QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing); + QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight); + QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY); + QFixed topSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.topSideBearing); + QFixed bottomSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.bottomSideBearing); + QFixed width = advanceWidth - leftSideBearing - rightSideBearing; + QFixed height = advanceHeight - topSideBearing - bottomSideBearing; + return glyph_metrics_t(leftSideBearing, + -verticalOriginY + topSideBearing, + width, + height, + advanceWidth, + 0); + } else { + qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); + } + + return glyph_metrics_t(); +} + +QFixed QWindowsFontEngineDirectWrite::capHeight() const +{ + if (m_capHeight <= 0) + return calculatedCapHeight(); + + return m_capHeight; +} + +QFixed QWindowsFontEngineDirectWrite::xHeight() const +{ + return m_xHeight; +} + +qreal QWindowsFontEngineDirectWrite::maxCharWidth() const +{ + return m_maxAdvanceWidth.toReal(); +} + +QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) +{ + QImage im = imageForGlyph(glyph, subPixelPosition, glyphMargin(Format_A8), t); + + QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); + + for (int y=0; y(im.constScanLine(y)); + uchar *dst = alphaMap.scanLine(y); + for (int x=0; xpow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.); + ++dst; + ++src; + } + } + + return alphaMap; +} + +QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) +{ + return alphaMapForGlyph(glyph, subPixelPosition, QTransform()); +} + +bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const +{ + return true; +} + +QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, + QFixed subPixelPosition, + int margin, + const QTransform &originalTransform, + const QColor &color) +{ + UINT16 glyphIndex = t; + FLOAT glyphAdvance = 0; + + DWRITE_GLYPH_OFFSET glyphOffset; + glyphOffset.advanceOffset = 0; + glyphOffset.ascenderOffset = 0; + + DWRITE_GLYPH_RUN glyphRun; + glyphRun.fontFace = m_directWriteFontFace; + glyphRun.fontEmSize = fontDef.pixelSize; + glyphRun.glyphCount = 1; + glyphRun.glyphIndices = &glyphIndex; + glyphRun.glyphAdvances = &glyphAdvance; + glyphRun.isSideways = false; + glyphRun.bidiLevel = 0; + glyphRun.glyphOffsets = &glyphOffset; + + QTransform xform = originalTransform; + if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) + xform.scale(fontDef.stretch / 100.0, 1.0); + + DWRITE_MATRIX transform; + transform.dx = subPixelPosition.toReal(); + transform.dy = 0; + transform.m11 = xform.m11(); + transform.m12 = xform.m12(); + transform.m21 = xform.m21(); + transform.m22 = xform.m22(); + + DWRITE_RENDERING_MODE renderMode = + hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); + DWRITE_MEASURING_MODE measureMode = + renderModeToMeasureMode(renderMode); + + IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; + HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &glyphRun, + 1.0f, + &transform, + renderMode, + measureMode, + 0.0, 0.0, + &glyphAnalysis + ); + + if (SUCCEEDED(hr)) { + RECT rect; + glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); + + if (rect.top == rect.bottom || rect.left == rect.right) + return QImage(); + + QRect boundingRect = QRect(QPoint(rect.left - margin, + rect.top - margin), + QPoint(rect.right + margin, + rect.bottom + margin)); + + + const int width = boundingRect.width() - 1; // -1 due to Qt's off-by-one definition of a QRect + const int height = boundingRect.height() - 1; + + QImage image; +#if defined(QT_USE_DIRECTWRITE2) + HRESULT hr = DWRITE_E_NOCOLOR; + IDWriteColorGlyphRunEnumerator *enumerator = 0; + IDWriteFactory2 *factory2 = nullptr; + if (glyphFormat == QFontEngine::Format_ARGB + && SUCCEEDED(m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), + reinterpret_cast(&factory2)))) { + hr = factory2->TranslateColorGlyphRun(0.0f, + 0.0f, + &glyphRun, + NULL, + measureMode, + NULL, + 0, + &enumerator); + image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); + image.fill(0); + } else +#endif + { + image = QImage(width, height, QImage::Format_RGB32); + image.fill(0xffffffff); + } + +#if defined(QT_USE_DIRECTWRITE2) + BOOL ok = true; + + if (SUCCEEDED(hr)) { + while (SUCCEEDED(hr) && ok) { + const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun = 0; + hr = enumerator->GetCurrentRun(&colorGlyphRun); + if (FAILED(hr)) { // No colored runs, only outline + qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::GetCurrentRun failed", __FUNCTION__); + break; + } + + IDWriteGlyphRunAnalysis *colorGlyphsAnalysis = NULL; + hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &colorGlyphRun->glyphRun, + 1.0f, + &transform, + renderMode, + measureMode, + 0.0, 0.0, + &colorGlyphsAnalysis + ); + if (FAILED(hr)) { + qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed for color run", __FUNCTION__); + break; + } + + float r, g, b, a; + if (colorGlyphRun->paletteIndex == 0xFFFF) { + r = float(color.redF()); + g = float(color.greenF()); + b = float(color.blueF()); + a = float(color.alphaF()); + } else { + r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f); + g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f); + b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f); + a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f); + } + + if (!qFuzzyIsNull(a)) { + renderGlyphRun(&image, + r, + g, + b, + a, + colorGlyphsAnalysis, + boundingRect); + } + colorGlyphsAnalysis->Release(); + + hr = enumerator->MoveNext(&ok); + if (FAILED(hr)) { + qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::MoveNext failed", __FUNCTION__); + break; + } + } + } else +#endif + { + float r, g, b, a; + if (glyphFormat == QFontEngine::Format_ARGB) { + r = float(color.redF()); + g = float(color.greenF()); + b = float(color.blueF()); + a = float(color.alphaF()); + } else { + r = g = b = a = 0.0; + } + + renderGlyphRun(&image, + r, + g, + b, + a, + glyphAnalysis, + boundingRect); + } + + glyphAnalysis->Release(); + return image; + } else { + qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed", __FUNCTION__); + return QImage(); + } +} + + +void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, + float r, + float g, + float b, + float a, + IDWriteGlyphRunAnalysis *glyphAnalysis, + const QRect &boundingRect) +{ + const int width = destination->width(); + const int height = destination->height(); + + r *= 255.0; + g *= 255.0; + b *= 255.0; + + const int size = width * height * 3; + if (size > 0) { + RECT rect; + rect.left = boundingRect.left(); + rect.top = boundingRect.top(); + rect.right = boundingRect.right(); + rect.bottom = boundingRect.bottom(); + + QVarLengthArray alphaValueArray(size); + BYTE *alphaValues = alphaValueArray.data(); + memset(alphaValues, 0, size); + + HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, + &rect, + alphaValues, + size); + if (SUCCEEDED(hr)) { + if (destination->hasAlphaChannel()) { + for (int y = 0; y < height; ++y) { + uint *dest = reinterpret_cast(destination->scanLine(y)); + BYTE *src = alphaValues + width * 3 * y; + + for (int x = 0; x < width; ++x) { + float redAlpha = a * *src++ / 255.0; + float greenAlpha = a * *src++ / 255.0; + float blueAlpha = a * *src++ / 255.0; + float averageAlpha = (redAlpha + greenAlpha + blueAlpha) / 3.0; + + QRgb currentRgb = dest[x]; + dest[x] = qRgba(qRound(qRed(currentRgb) * (1.0 - averageAlpha) + averageAlpha * r), + qRound(qGreen(currentRgb) * (1.0 - averageAlpha) + averageAlpha * g), + qRound(qBlue(currentRgb) * (1.0 - averageAlpha) + averageAlpha * b), + qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255)); + } + } + + } else { + for (int y = 0; y < height; ++y) { + uint *dest = reinterpret_cast(destination->scanLine(y)); + BYTE *src = alphaValues + width * 3 * y; + + for (int x = 0; x < width; ++x) { + dest[x] = *(src + 0) << 16 + | *(src + 1) << 8 + | *(src + 2); + + src += 3; + } + } + } + } else { + qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); + } + } else { + glyphAnalysis->Release(); + qWarning("%s: Glyph has no bounds", __FUNCTION__); + } +} + +QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t, + QFixed subPixelPosition, + const QTransform &xform) +{ + QImage mask = imageForGlyph(t, + subPixelPosition, + glyphMargin(QFontEngine::Format_A32), + xform); + + return mask.depth() == 32 + ? mask + : mask.convertToFormat(QImage::Format_RGB32); +} + +QFontEngine *QWindowsFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const +{ + QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(m_directWriteFontFace, + pixelSize, + m_fontEngineData); + + fontEngine->fontDef = fontDef; + fontEngine->fontDef.pixelSize = pixelSize; + if (!m_uniqueFamilyName.isEmpty()) { + fontEngine->setUniqueFamilyName(m_uniqueFamilyName); + QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); + static_cast(pfdb)->refUniqueFont(m_uniqueFamilyName); + } + + return fontEngine; +} + +Qt::HANDLE QWindowsFontEngineDirectWrite::handle() const +{ + return m_directWriteFontFace; +} + +void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, + int dpi) +{ + fontDef = request; + + if (fontDef.pointSize < 0) + fontDef.pointSize = fontDef.pixelSize * 72. / dpi; + else if (fontDef.pixelSize == -1) + fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); +} + +QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName) +{ + const QString substitute = + QWinRegistryKey(HKEY_LOCAL_MACHINE, + LR"(Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes)") + .stringValue(familyName); + return substitute.isEmpty() ? familyName : substitute; +} + +glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, + QFixed subPixelPosition, + const QTransform &originalTransform, + GlyphFormat format) +{ + Q_UNUSED(format); + + QTransform matrix = originalTransform; + if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) + matrix.scale(fontDef.stretch / 100.0, 1.0); + + glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance + + UINT16 glyphIndex = glyph; + FLOAT glyphAdvance = 0; + + DWRITE_GLYPH_OFFSET glyphOffset; + glyphOffset.advanceOffset = 0; + glyphOffset.ascenderOffset = 0; + + DWRITE_GLYPH_RUN glyphRun; + glyphRun.fontFace = m_directWriteFontFace; + glyphRun.fontEmSize = fontDef.pixelSize; + glyphRun.glyphCount = 1; + glyphRun.glyphIndices = &glyphIndex; + glyphRun.glyphAdvances = &glyphAdvance; + glyphRun.isSideways = false; + glyphRun.bidiLevel = 0; + glyphRun.glyphOffsets = &glyphOffset; + + DWRITE_MATRIX transform; + transform.dx = subPixelPosition.toReal(); + transform.dy = 0; + transform.m11 = matrix.m11(); + transform.m12 = matrix.m12(); + transform.m21 = matrix.m21(); + transform.m22 = matrix.m22(); + + DWRITE_RENDERING_MODE renderMode = + hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); + DWRITE_MEASURING_MODE measureMode = renderModeToMeasureMode(renderMode); + + IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; + HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( + &glyphRun, + 1.0f, + &transform, + renderMode, + measureMode, + 0.0, 0.0, + &glyphAnalysis + ); + + if (SUCCEEDED(hr)) { + RECT rect; + glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); + glyphAnalysis->Release(); + + int margin = glyphMargin(format); + + if (rect.left == rect.right || rect.top == rect.bottom) + return glyph_metrics_t(); + + return glyph_metrics_t(rect.left, + rect.top, + rect.right - rect.left + margin * 2, + rect.bottom - rect.top + margin * 2, + bbox.xoff, bbox.yoff); + } else { + return glyph_metrics_t(); + } +} + +QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color) +{ + return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_ARGB), t, color); +} + +QT_END_NAMESPACE + +#endif // QT_NO_DIRECTWRITE diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h new file mode 100644 index 0000000000..6e79190ce4 --- /dev/null +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtGui module 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSFONTENGINEDIRECTWRITE_H +#define QWINDOWSFONTENGINEDIRECTWRITE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#ifndef QT_NO_DIRECTWRITE + +#include +#include + +struct IDWriteFont; +struct IDWriteFontFace; +struct IDWriteFontFile; +struct IDWriteFactory; +struct IDWriteBitmapRenderTarget; +struct IDWriteGdiInterop; +struct IDWriteGlyphRunAnalysis; + +QT_BEGIN_NAMESPACE + +class QWindowsFontEngineData; + +class QWindowsFontEngineDirectWrite : public QFontEngine +{ + Q_DISABLE_COPY_MOVE(QWindowsFontEngineDirectWrite) +public: + explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, + qreal pixelSize, + const QSharedPointer &d); + ~QWindowsFontEngineDirectWrite() override; + + void initFontInfo(const QFontDef &request, int dpi); + + QFixed lineThickness() const override; + QFixed underlinePosition() const override; + bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; + 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; + void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; + + void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, + QPainterPath *path, QTextItem::RenderFlags flags) override; + + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; + glyph_metrics_t boundingBox(glyph_t g) override; + glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, + const QTransform &matrix, GlyphFormat) override; + + QFixed capHeight() const override; + QFixed xHeight() const override; + qreal maxCharWidth() const override; + FaceId faceId() const override; + + bool supportsSubPixelPositions() const override; + + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) override; + QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override; + QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override; + QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override; + + QFontEngine *cloneWithSize(qreal pixelSize) const override; + Qt::HANDLE handle() const override; + + const QSharedPointer &fontEngineData() const { return m_fontEngineData; } + + static QString fontNameSubstitute(const QString &familyName); + + IDWriteFontFace *directWriteFontFace() const { return m_directWriteFontFace; } + + void setUniqueFamilyName(const QString &newName) { m_uniqueFamilyName = newName; } + + void initializeHeightMetrics() const override; + +private: + QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, 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); + static QString filenameFromFontFile(IDWriteFontFile *fontFile); + + const QSharedPointer m_fontEngineData; + + IDWriteFontFace *m_directWriteFontFace; + IDWriteBitmapRenderTarget *m_directWriteBitmapRenderTarget; + + QFixed m_lineThickness; + QFixed m_underlinePosition; + int m_unitsPerEm; + QFixed m_capHeight; + QFixed m_xHeight; + QFixed m_maxAdvanceWidth; + FaceId m_faceId; + QString m_uniqueFamilyName; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DIRECTWRITE + +#endif // QWINDOWSFONTENGINEDIRECTWRITE_H diff --git a/src/gui/text/windows/qwindowsnativeimage.cpp b/src/gui/text/windows/qwindowsnativeimage.cpp new file mode 100644 index 0000000000..ad277ea7cd --- /dev/null +++ b/src/gui/text/windows/qwindowsnativeimage.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#include "qwindowsnativeimage_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +typedef struct { + BITMAPINFOHEADER bmiHeader; + DWORD redMask; + DWORD greenMask; + DWORD blueMask; +} BITMAPINFO_MASK; + +/*! + \class QWindowsNativeImage + \brief Windows Native image + + Note that size can be 0 (widget autotests with zero size), which + causes CreateDIBSection() to fail. + + \sa QWindowsBackingStore + \internal +*/ + +static inline HDC createDC() +{ + HDC display_dc = GetDC(0); + HDC hdc = CreateCompatibleDC(display_dc); + ReleaseDC(0, display_dc); + Q_ASSERT(hdc); + return hdc; +} + +static inline HBITMAP createDIB(HDC hdc, int width, int height, + QImage::Format format, + uchar **bitsIn) +{ + BITMAPINFO_MASK bmi; + memset(&bmi, 0, sizeof(bmi)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; // top-down. + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biSizeImage = 0; + + if (format == QImage::Format_RGB16) { + bmi.bmiHeader.biBitCount = 16; + bmi.bmiHeader.biCompression = BI_BITFIELDS; + bmi.redMask = 0xF800; + bmi.greenMask = 0x07E0; + bmi.blueMask = 0x001F; + } else { + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.redMask = 0; + bmi.greenMask = 0; + bmi.blueMask = 0; + } + + uchar *bits = nullptr; + HBITMAP bitmap = CreateDIBSection(hdc, reinterpret_cast(&bmi), + DIB_RGB_COLORS, reinterpret_cast(&bits), 0, 0); + if (Q_UNLIKELY(!bitmap || !bits)) { + qFatal("%s: CreateDIBSection failed (%dx%d, format: %d)", __FUNCTION__, + width, height, int(format)); + } + + *bitsIn = bits; + return bitmap; +} + +QWindowsNativeImage::QWindowsNativeImage(int width, int height, + QImage::Format format) : + m_hdc(createDC()) +{ + if (width != 0 && height != 0) { + uchar *bits; + m_bitmap = createDIB(m_hdc, width, height, format, &bits); + m_null_bitmap = static_cast(SelectObject(m_hdc, m_bitmap)); + m_image = QImage(bits, width, height, format); + Q_ASSERT(m_image.paintEngine()->type() == QPaintEngine::Raster); + static_cast(m_image.paintEngine())->setDC(m_hdc); + } else { + m_image = QImage(width, height, format); + } + + GdiFlush(); +} + +QWindowsNativeImage::~QWindowsNativeImage() +{ + if (m_hdc) { + if (m_bitmap) { + if (m_null_bitmap) + SelectObject(m_hdc, m_null_bitmap); + DeleteObject(m_bitmap); + } + DeleteDC(m_hdc); + } +} + +QImage::Format QWindowsNativeImage::systemFormat() +{ + static int depth = -1; + if (depth == -1) { + if (HDC defaultDC = GetDC(0)) { + depth = GetDeviceCaps(defaultDC, BITSPIXEL); + ReleaseDC(0, defaultDC); + } else { + // FIXME Same remark as in QWindowsFontDatabase::defaultVerticalDPI() + // BONUS FIXME: Is 32 too generous/optimistic? + depth = 32; + } + } + return depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; +} + +QT_END_NAMESPACE diff --git a/src/gui/text/windows/qwindowsnativeimage_p.h b/src/gui/text/windows/qwindowsnativeimage_p.h new file mode 100644 index 0000000000..050ecbf03c --- /dev/null +++ b/src/gui/text/windows/qwindowsnativeimage_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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$ +** +****************************************************************************/ + +#ifndef QWINDOWSNATIVEIMAGE_H +#define QWINDOWSNATIVEIMAGE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QWindowsNativeImage +{ + Q_DISABLE_COPY_MOVE(QWindowsNativeImage) +public: + QWindowsNativeImage(int width, int height, + QImage::Format format); + + ~QWindowsNativeImage(); + + inline int width() const { return m_image.width(); } + inline int height() const { return m_image.height(); } + + QImage &image() { return m_image; } + const QImage &image() const { return m_image; } + + HDC hdc() const { return m_hdc; } + + static QImage::Format systemFormat(); + +private: + const HDC m_hdc; + QImage m_image; + + HBITMAP m_bitmap = 0; + HBITMAP m_null_bitmap = 0; +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSNATIVEIMAGE_H diff --git a/src/gui/text/windows/windows.pri b/src/gui/text/windows/windows.pri new file mode 100644 index 0000000000..477437833a --- /dev/null +++ b/src/gui/text/windows/windows.pri @@ -0,0 +1,41 @@ +SOURCES += \ + text/windows/qwindowsfontdatabase.cpp \ + text/windows/qwindowsfontdatabasebase.cpp \ + text/windows/qwindowsfontengine.cpp \ + text/windows/qwindowsnativeimage.cpp + +HEADERS += \ + text/windows/qwindowsfontdatabase_p.h \ + text/windows/qwindowsfontdatabasebase_p.h \ + text/windows/qwindowsfontengine_p.h \ + text/windows/qwindowsnativeimage_p.h + +qtConfig(freetype) { + SOURCES += text/windows/qwindowsfontdatabase_ft.cpp + HEADERS += text/windows/qwindowsfontdatabase_ft_p.h + QMAKE_USE_PRIVATE += freetype +} + +qtConfig(directwrite):qtConfig(direct2d) { + qtConfig(directwrite3) { + QMAKE_USE_PRIVATE += dwrite_3 + DEFINES *= QT_USE_DIRECTWRITE3 QT_USE_DIRECTWRITE2 + + SOURCES += text/windows/qwindowsdirectwritefontdatabase.cpp + HEADERS += text/windows/qwindowsdirectwritefontdatabase_p.h + } else: qtConfig(directwrite2) { + QMAKE_USE_PRIVATE += dwrite_2 + DEFINES *= QT_USE_DIRECTWRITE2 + } else { + QMAKE_USE_PRIVATE += dwrite + } + QMAKE_USE_PRIVATE += d2d1 + + SOURCES += text/windows/qwindowsfontenginedirectwrite.cpp + HEADERS += text/windows/qwindowsfontenginedirectwrite_p.h +} else { + DEFINES *= QT_NO_DIRECTWRITE +} + +QMAKE_USE_PRIVATE += advapi32 ole32 user32 gdi32 +mingw: QMAKE_USE_PRIVATE += uuid diff --git a/src/platformsupport/fontdatabases/.prev_CMakeLists.txt b/src/platformsupport/fontdatabases/.prev_CMakeLists.txt index be84811a9e..a19195bc02 100644 --- a/src/platformsupport/fontdatabases/.prev_CMakeLists.txt +++ b/src/platformsupport/fontdatabases/.prev_CMakeLists.txt @@ -34,64 +34,3 @@ qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_fontconfig LIBRARIES Fontconfig::Fontconfig ) - -qt_extend_target(FontDatabaseSupport CONDITION WIN32 - SOURCES - windows/qwindowsfontdatabase.cpp windows/qwindowsfontdatabase_p.h - windows/qwindowsfontdatabasebase.cpp windows/qwindowsfontdatabasebase_p.h - windows/qwindowsfontengine.cpp windows/qwindowsfontengine_p.h - windows/qwindowsnativeimage.cpp windows/qwindowsnativeimage_p.h - LIBRARIES - advapi32 - gdi32 - ole32 - user32 - PUBLIC_LIBRARIES - Qt::GuiPrivate -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_freetype AND WIN32 - SOURCES - windows/qwindowsfontdatabase_ft.cpp windows/qwindowsfontdatabase_ft_p.h - LIBRARIES - WrapFreetype::WrapFreetype -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 - SOURCES - windows/qwindowsfontenginedirectwrite.cpp windows/qwindowsfontenginedirectwrite_p.h - LIBRARIES - d2d1 -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite3 AND WIN32 - SOURCES - windows/qwindowsdirectwritefontdatabase.cpp windows/qwindowsdirectwritefontdatabase_p.h - DEFINES - QT_USE_DIRECTWRITE2 - QT_USE_DIRECTWRITE3 - LIBRARIES - dwrite_3 -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite2 AND WIN32 AND NOT QT_FEATURE_directwrite3 - DEFINES - QT_USE_DIRECTWRITE2 - LIBRARIES - dwrite_2 -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 AND NOT QT_FEATURE_directwrite2 AND NOT QT_FEATURE_directwrite3 - LIBRARIES - dwrite -) - -qt_extend_target(FontDatabaseSupport CONDITION WIN32 AND (NOT QT_FEATURE_direct2d OR NOT QT_FEATURE_directwrite) - DEFINES - QT_NO_DIRECTWRITE -) - -qt_extend_target(FontDatabaseSupport CONDITION MINGW AND WIN32 - LIBRARIES - uuid -) diff --git a/src/platformsupport/fontdatabases/CMakeLists.txt b/src/platformsupport/fontdatabases/CMakeLists.txt index 8b37257ded..2f4519ec30 100644 --- a/src/platformsupport/fontdatabases/CMakeLists.txt +++ b/src/platformsupport/fontdatabases/CMakeLists.txt @@ -46,64 +46,3 @@ if(TARGET WrapFreetype::WrapFreetype) ) endif() # special case end - -qt_extend_target(FontDatabaseSupport CONDITION WIN32 - SOURCES - windows/qwindowsfontdatabase.cpp windows/qwindowsfontdatabase_p.h - windows/qwindowsfontdatabasebase.cpp windows/qwindowsfontdatabasebase_p.h - windows/qwindowsfontengine.cpp windows/qwindowsfontengine_p.h - windows/qwindowsnativeimage.cpp windows/qwindowsnativeimage_p.h - LIBRARIES - advapi32 - gdi32 - ole32 - user32 - PUBLIC_LIBRARIES - Qt::GuiPrivate -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_freetype AND WIN32 - SOURCES - windows/qwindowsfontdatabase_ft.cpp windows/qwindowsfontdatabase_ft_p.h - LIBRARIES - WrapFreetype::WrapFreetype -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 - SOURCES - windows/qwindowsfontenginedirectwrite.cpp windows/qwindowsfontenginedirectwrite_p.h - LIBRARIES - d2d1 -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite3 AND WIN32 - SOURCES - windows/qwindowsdirectwritefontdatabase.cpp windows/qwindowsdirectwritefontdatabase_p.h - DEFINES - QT_USE_DIRECTWRITE2 - QT_USE_DIRECTWRITE3 - LIBRARIES - dwrite_3 -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND QT_FEATURE_directwrite2 AND WIN32 AND NOT QT_FEATURE_directwrite3 - DEFINES - QT_USE_DIRECTWRITE2 - LIBRARIES - dwrite_2 -) - -qt_extend_target(FontDatabaseSupport CONDITION QT_FEATURE_direct2d AND QT_FEATURE_directwrite AND WIN32 AND NOT QT_FEATURE_directwrite2 AND NOT QT_FEATURE_directwrite3 - LIBRARIES - dwrite -) - -qt_extend_target(FontDatabaseSupport CONDITION WIN32 AND (NOT QT_FEATURE_direct2d OR NOT QT_FEATURE_directwrite) - DEFINES - QT_NO_DIRECTWRITE -) - -qt_extend_target(FontDatabaseSupport CONDITION MINGW AND WIN32 - LIBRARIES - uuid -) diff --git a/src/platformsupport/fontdatabases/fontdatabases.pro b/src/platformsupport/fontdatabases/fontdatabases.pro index d597a0d6c2..5406291cea 100644 --- a/src/platformsupport/fontdatabases/fontdatabases.pro +++ b/src/platformsupport/fontdatabases/fontdatabases.pro @@ -15,8 +15,4 @@ qtConfig(fontconfig) { include($$PWD/fontconfig/fontconfig.pri) } -win32 { - include($$PWD/windows/windows.pri) -} - load(qt_module) diff --git a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp deleted file mode 100644 index d2fb909dea..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp +++ /dev/null @@ -1,478 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include "qwindowsdirectwritefontdatabase_p.h" -#include "qwindowsfontenginedirectwrite_p.h" -#include "qwindowsfontdatabase_p.h" - -#include -#include -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -#ifdef QT_USE_DIRECTWRITE3 - -// Defined in gui/text/qfontdatabase.cpp -Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script); - -QWindowsDirectWriteFontDatabase::QWindowsDirectWriteFontDatabase() -{ - qCDebug(lcQpaFonts) << "Creating DirectWrite database"; -} - -QWindowsDirectWriteFontDatabase::~QWindowsDirectWriteFontDatabase() -{ - for (auto it = m_populatedFonts.begin(); it != m_populatedFonts.end(); ++it) - it.value()->Release(); -} - -QString QWindowsDirectWriteFontDatabase::localeString(IDWriteLocalizedStrings *names, - wchar_t localeName[]) -{ - uint index; - BOOL exists; - if (SUCCEEDED(names->FindLocaleName(localeName, &index, &exists)) && exists) { - uint length; - if (SUCCEEDED(names->GetStringLength(index, &length)) && length > 0) { - QVarLengthArray buffer(int(length) + 1); - if (SUCCEEDED(names->GetString(index, buffer.data(), length + 1))) - return QString::fromWCharArray(buffer.data()); - } - } - - return QString(); -} - -static QFont::Stretch fromDirectWriteStretch(DWRITE_FONT_STRETCH stretch) -{ - switch (stretch) { - case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: return QFont::UltraCondensed; - case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: return QFont::ExtraCondensed; - case DWRITE_FONT_STRETCH_CONDENSED: return QFont::Condensed; - case DWRITE_FONT_STRETCH_SEMI_CONDENSED: return QFont::SemiCondensed; - case DWRITE_FONT_STRETCH_NORMAL: return QFont::Unstretched; - case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return QFont::SemiExpanded; - case DWRITE_FONT_STRETCH_EXPANDED: return QFont::Expanded; - case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return QFont::ExtraExpanded; - case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return QFont::UltraExpanded; - default: return QFont::AnyStretch; - } -} - -static QFont::Weight fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight) -{ - return QPlatformFontDatabase::weightFromInteger(int(weight)); -} - -static DWRITE_FONT_STYLE toDirectWriteStyle(QFont::Style style) -{ - switch (style) { - case QFont::StyleNormal: return DWRITE_FONT_STYLE_NORMAL; - case QFont::StyleOblique: return DWRITE_FONT_STYLE_OBLIQUE; - case QFont::StyleItalic: return DWRITE_FONT_STYLE_ITALIC; - default: return DWRITE_FONT_STYLE_NORMAL; - } -} - -static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style) -{ - switch (style) { - case DWRITE_FONT_STYLE_NORMAL: return QFont::StyleNormal; - case DWRITE_FONT_STYLE_OBLIQUE: return QFont::StyleOblique; - case DWRITE_FONT_STYLE_ITALIC: return QFont::StyleItalic; - default: return QFont::StyleNormal; - } -} - -void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) -{ - auto it = m_populatedFonts.find(familyName); - IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr; - if (fontFamily == nullptr) { - qCWarning(lcQpaFonts) << "Cannot find" << familyName << "in list of fonts"; - return; - } - - qCDebug(lcQpaFonts) << "Populate family:" << familyName; - - 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 QString foundryName; // No such concept. - const bool scalable = true; - const bool antialias = false; - const int size = SMOOTH_SCALABLE; - - IDWriteFontList *matchingFonts; - if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR, - DWRITE_FONT_STRETCH_NORMAL, - DWRITE_FONT_STYLE_NORMAL, - &matchingFonts))) { - for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) { - IDWriteFont *font; - if (SUCCEEDED(matchingFonts->GetFont(j, &font))) { - IDWriteFont1 *font1 = nullptr; - if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1), - reinterpret_cast(&font1)))) { - qCWarning(lcQpaFonts) << "COM object does not support IDWriteFont1"; - continue; - } - - QString defaultLocaleFamilyName; - QString englishLocaleFamilyName; - - IDWriteFontFamily *fontFamily2; - if (SUCCEEDED(font1->GetFontFamily(&fontFamily2))) { - IDWriteLocalizedStrings *names; - if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) { - defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); - englishLocaleFamilyName = localeString(names, englishLocale); - - names->Release(); - } - - fontFamily2->Release(); - } - - if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty()) - englishLocaleFamilyName = familyName; - - { - IDWriteLocalizedStrings *names; - if (SUCCEEDED(font1->GetFaceNames(&names))) { - QString defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); - 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(); - - qCDebug(lcQpaFonts) << "Family" << familyName << "has english variant" << englishLocaleStyleName << ", in default locale:" << defaultLocaleStyleName << stretch << style << weight << fixed; - - 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(qbswap(MAKE_TAG('O','S','/','2')), - &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; - } - } - } - - 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(); - } - - if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) { - QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); - } - - face->Release(); - } - - names->Release(); - } - } - - font1->Release(); - font->Release(); - } - } - - matchingFonts->Release(); - } -} - -QFontEngine *QWindowsDirectWriteFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) -{ - IDWriteFontFace *face = reinterpret_cast(handle); - Q_ASSERT(face != nullptr); - - QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(face, fontDef.pixelSize, data()); - fontEngine->initFontInfo(fontDef, defaultVerticalDPI()); - - return fontEngine; -} - -QStringList QWindowsDirectWriteFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - QStringList result; - result.append(familyForStyleHint(styleHint)); - result.append(extraTryFontsForFamily(family)); - result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); - - qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint - << script << result; - return result; -} - -QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont) -{ - qCDebug(lcQpaFonts) << "Adding application font" << fileName; - - QByteArray loadedData = fontData; - if (loadedData.isEmpty()) { - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly)) { - qCWarning(lcQpaFonts) << "Cannot open" << fileName << "for reading."; - return QStringList(); - } - loadedData = file.readAll(); - } - - IDWriteFontFace *face = createDirectWriteFace(loadedData); - if (face == nullptr) { - 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"; - - 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); - - QStringList ret; - IDWriteFontFace3 *face3 = nullptr; - if (SUCCEEDED(face->QueryInterface(__uuidof(IDWriteFontFace3), - reinterpret_cast(&face3)))) { - QString defaultLocaleFamilyName; - QString englishLocaleFamilyName; - - IDWriteLocalizedStrings *names; - if (SUCCEEDED(face3->GetFamilyNames(&names))) { - defaultLocaleFamilyName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); - englishLocaleFamilyName = localeString(names, englishLocale); - - names->Release(); - } - - QString defaultLocaleStyleName; - QString englishLocaleStyleName; - if (SUCCEEDED(face3->GetFaceNames(&names))) { - defaultLocaleStyleName = hasDefaultLocale ? localeString(names, defaultLocale) : QString(); - englishLocaleStyleName = localeString(names, englishLocale); - - names->Release(); - } - - 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); - } - - ret.append(englishLocaleFamilyName); - QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); - } - - 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); - } - - ret.append(defaultLocaleFamilyName); - QPlatformFontDatabase::registerFont(defaultLocaleFamilyName, defaultLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); - face->AddRef(); - } - - face3->Release(); - } else { - qCWarning(lcQpaFonts) << "Unable to query IDWriteFontFace3 interface from font face."; - } - - face->Release(); - - return ret; -} - -void QWindowsDirectWriteFontDatabase::releaseHandle(void *handle) -{ - IDWriteFontFace *face = reinterpret_cast(handle); - face->Release(); -} - -bool QWindowsDirectWriteFontDatabase::fontsAlwaysScalable() const -{ - return true; -} - -bool QWindowsDirectWriteFontDatabase::isPrivateFontFamily(const QString &family) const -{ - Q_UNUSED(family); - return false; -} - -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"; - - QString defaultFontName = defaultFont().family(); - QString systemDefaultFontName = systemDefaultFont().family(); - - IDWriteFontCollection *fontCollection; - if (SUCCEEDED(data()->directWriteFactory->GetSystemFontCollection(&fontCollection))) { - for (uint i = 0; i < fontCollection->GetFontFamilyCount(); ++i) { - IDWriteFontFamily *fontFamily; - if (SUCCEEDED(fontCollection->GetFontFamily(i, &fontFamily))) { - QString defaultLocaleName; - QString englishLocaleName; - - IDWriteLocalizedStrings *names; - if (SUCCEEDED(fontFamily->GetFamilyNames(&names))) { - if (hasDefaultLocale) - defaultLocaleName = localeString(names, defaultLocale); - - 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); - fontFamily->AddRef(); - - if (defaultLocaleName == defaultFontName && defaultFontName != systemDefaultFontName) { - qDebug(lcQpaFonts) << "Adding default font" << systemDefaultFontName << "as alternative to" << defaultLocaleName; - - m_populatedFonts.insert(systemDefaultFontName, fontFamily); - fontFamily->AddRef(); - } - } - - if (!englishLocaleName.isEmpty() && englishLocaleName != defaultLocaleName) { - registerFontFamily(englishLocaleName); - 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); - fontFamily->AddRef(); - } - } - - fontFamily->Release(); - } - } - } -} - -QFont QWindowsDirectWriteFontDatabase::defaultFont() const -{ - return QFont(QStringLiteral("Segoe UI")); -} - -#endif // QT_USE_DIRECTWRITE3 - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h deleted file mode 100644 index f46c57e6a5..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSDIRECTWRITEFONTDATABASE_P_H -#define QWINDOWSDIRECTWRITEFONTDATABASE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qwindowsfontdatabasebase_p.h" - -#include -#include - -struct IDWriteFactory; -struct IDWriteFont; -struct IDWriteFontFamily; -struct IDWriteLocalizedStrings; - -QT_BEGIN_NAMESPACE - -#ifdef QT_USE_DIRECTWRITE3 - -class QWindowsDirectWriteFontDatabase : public QWindowsFontDatabaseBase -{ - Q_DISABLE_COPY_MOVE(QWindowsDirectWriteFontDatabase) -public: - QWindowsDirectWriteFontDatabase(); - ~QWindowsDirectWriteFontDatabase() override; - - void populateFontDatabase() override; - void populateFamily(const QString &familyName) override; - QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) 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; - -private: - static QString localeString(IDWriteLocalizedStrings *names, wchar_t localeName[]); - - QHash m_populatedFonts; -}; - -#endif // QT_USE_DIRECTWRITE3 - -QT_END_NAMESPACE - -#endif // QWINDOWSDIRECTWRITEFONTDATABASE_P_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp deleted file mode 100644 index 2beb35eb03..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ /dev/null @@ -1,1231 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -#include "qwindowsfontdatabase_p.h" -#include "qwindowsfontdatabase_ft_p.h" // for default font -#include "qwindowsfontengine_p.h" -#include "qwindowsfontenginedirectwrite_p.h" -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#if !defined(QT_NO_DIRECTWRITE) -# if defined(QT_USE_DIRECTWRITE2) -# include -# else -# include -# endif -# include -# include "qwindowsdirectwritefontdatabase_p.h" -#endif - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts") - -#ifndef QT_NO_DIRECTWRITE -// ### fixme: Consider direct linking of dwrite.dll once Windows Vista pre SP2 is dropped (QTBUG-49711) - -typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **); - -static inline bool useDirectWrite(QFont::HintingPreference hintingPreference, - const QString &familyName = QString(), - bool isColorFont = false) -{ - const unsigned options = QWindowsFontDatabase::fontOptions(); - if (Q_UNLIKELY(options & QWindowsFontDatabase::DontUseDirectWriteFonts)) - return false; - - // At some scales, GDI will misrender the MingLiU font, so we force use of - // DirectWrite to work around the issue. - if (Q_UNLIKELY(familyName.startsWith(QLatin1String("MingLiU")))) - return true; - - if (isColorFont) - return (options & QWindowsFontDatabase::DontUseColorFonts) == 0; - - return hintingPreference == QFont::PreferNoHinting - || hintingPreference == QFont::PreferVerticalHinting - || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting); -} -#endif // !QT_NO_DIRECTWRITE - -/*! - \struct QWindowsFontEngineData - \brief Static constant data shared by the font engines. -*/ - -QWindowsFontEngineData::QWindowsFontEngineData() - : fontSmoothingGamma(QWindowsFontDatabase::fontSmoothingGamma()) -{ - // from qapplication_win.cpp - UINT result = 0; - if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &result, 0)) - clearTypeEnabled = (result == FE_FONTSMOOTHINGCLEARTYPE); - - const qreal gray_gamma = 2.31; - for (int i=0; i<256; ++i) - pow_gamma[i] = uint(qRound(qPow(i / qreal(255.), gray_gamma) * 2047)); - - HDC displayDC = GetDC(0); - hdc = CreateCompatibleDC(displayDC); - ReleaseDC(0, displayDC); -} - -unsigned QWindowsFontDatabase::m_fontOptions = 0; - -void QWindowsFontDatabase::setFontOptions(unsigned options) -{ - m_fontOptions = options & (QWindowsFontDatabase::DontUseDirectWriteFonts | - QWindowsFontDatabase::DontUseColorFonts); -} - -unsigned QWindowsFontDatabase::fontOptions() -{ - return m_fontOptions; -} - -qreal QWindowsFontDatabase::fontSmoothingGamma() -{ - int winSmooth; - qreal result = 1; - if (SystemParametersInfo(0x200C /* SPI_GETFONTSMOOTHINGCONTRAST */, 0, &winSmooth, 0)) - result = qreal(winSmooth) / qreal(1000.0); - - // Safeguard ourselves against corrupt registry values... - if (result > 5 || result < 1) - result = qreal(1.4); - return result; -} - -/*! - \class QWindowsFontDatabase - \brief Font database for Windows - - \note The Qt 4.8 WIndows font database employed a mechanism of - delayed population of the database again passing a font name - to EnumFontFamiliesEx(), working around the fact that - EnumFontFamiliesEx() does not list all fonts by default. - This should be introduced to QPA as well? - - \internal -*/ - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const QFontDef &def) -{ - QDebugStateSaver saver(d); - d.nospace(); - d.noquote(); - d << "QFontDef(Family=\"" << def.family << '"'; - if (!def.styleName.isEmpty()) - d << ", stylename=" << def.styleName; - d << ", pointsize=" << def.pointSize << ", pixelsize=" << def.pixelSize - << ", styleHint=" << def.styleHint << ", weight=" << def.weight - << ", stretch=" << def.stretch << ", hintingPreference=" - << def.hintingPreference << ')'; - return d; -} - -QDebug operator<<(QDebug d, const LOGFONT &lf) -{ - QDebugStateSaver saver(d); - d.nospace(); - d.noquote(); - d << "LOGFONT(\"" << QString::fromWCharArray(lf.lfFaceName) - << "\", lfWidth=" << lf.lfWidth << ", lfHeight=" << lf.lfHeight << ')'; - return d; -} -#endif // !QT_NO_DEBUG_STREAM - -static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) -{ - switch (charSet) { - case ANSI_CHARSET: - case EASTEUROPE_CHARSET: - case BALTIC_CHARSET: - case TURKISH_CHARSET: - return QFontDatabase::Latin; - case GREEK_CHARSET: - return QFontDatabase::Greek; - case RUSSIAN_CHARSET: - return QFontDatabase::Cyrillic; - case HEBREW_CHARSET: - return QFontDatabase::Hebrew; - case ARABIC_CHARSET: - return QFontDatabase::Arabic; - case THAI_CHARSET: - return QFontDatabase::Thai; - case GB2312_CHARSET: - return QFontDatabase::SimplifiedChinese; - case CHINESEBIG5_CHARSET: - return QFontDatabase::TraditionalChinese; - case SHIFTJIS_CHARSET: - return QFontDatabase::Japanese; - case HANGUL_CHARSET: - case JOHAB_CHARSET: - return QFontDatabase::Korean; - case VIETNAMESE_CHARSET: - return QFontDatabase::Vietnamese; - case SYMBOL_CHARSET: - return QFontDatabase::Symbol; - default: - break; - } - 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(); - for (int i = 0; i < name.length(); ++i) { - if (c[i].unicode() >= 0x100) - return true; - } - return false; -} - -namespace { - -static QString readName(bool unicode, const uchar *string, int length) -{ - QString out; - if (unicode) { - // utf16 - - length /= 2; - out.resize(length); - QChar *uc = out.data(); - for (int i = 0; i < length; ++i) - uc[i] = qt_getUShort(string + 2*i); - } else { - // Apple Roman - - out.resize(length); - QChar *uc = out.data(); - for (int i = 0; i < length; ++i) - uc[i] = QLatin1Char(char(string[i])); - } - return out; -} - -enum FieldTypeValue { - FamilyId = 1, - StyleId = 2, - PreferredFamilyId = 16, - PreferredStyleId = 17, -}; - -enum PlatformFieldValue { - PlatformId_Unicode = 0, - PlatformId_Apple = 1, - PlatformId_Microsoft = 3 -}; - -QFontNames qt_getCanonicalFontNames(const uchar *table, quint32 bytes) -{ - QFontNames out; - const int NameRecordSize = 12; - const int MS_LangIdEnglish = 0x009; - - // get the name table - quint16 count; - quint16 string_offset; - const unsigned char *names; - - if (bytes < 8) - return out; - - if (qt_getUShort(table) != 0) - return out; - - count = qt_getUShort(table + 2); - string_offset = qt_getUShort(table + 4); - names = table + 6; - - if (string_offset >= bytes || 6 + count*NameRecordSize > string_offset) - return out; - - enum PlatformIdType { - NotFound = 0, - Unicode = 1, - Apple = 2, - Microsoft = 3 - }; - - PlatformIdType idStatus[4] = { NotFound, NotFound, NotFound, NotFound }; - int ids[4] = { -1, -1, -1, -1 }; - - for (int i = 0; i < count; ++i) { - // search for the correct name entries - - quint16 platform_id = qt_getUShort(names + i*NameRecordSize); - quint16 encoding_id = qt_getUShort(names + 2 + i*NameRecordSize); - quint16 language_id = qt_getUShort(names + 4 + i*NameRecordSize); - quint16 name_id = qt_getUShort(names + 6 + i*NameRecordSize); - - PlatformIdType *idType = nullptr; - int *id = nullptr; - - switch (name_id) { - case FamilyId: - idType = &idStatus[0]; - id = &ids[0]; - break; - case StyleId: - idType = &idStatus[1]; - id = &ids[1]; - break; - case PreferredFamilyId: - idType = &idStatus[2]; - id = &ids[2]; - break; - case PreferredStyleId: - idType = &idStatus[3]; - id = &ids[3]; - break; - default: - continue; - } - - quint16 length = qt_getUShort(names + 8 + i*NameRecordSize); - quint16 offset = qt_getUShort(names + 10 + i*NameRecordSize); - if (DWORD(string_offset + offset + length) > bytes) - continue; - - if ((platform_id == PlatformId_Microsoft - && (encoding_id == 0 || encoding_id == 1)) - && ((language_id & 0x3ff) == MS_LangIdEnglish - || *idType < Microsoft)) { - *id = i; - *idType = Microsoft; - } - // not sure if encoding id 4 for Unicode is utf16 or ucs4... - else if (platform_id == PlatformId_Unicode && encoding_id < 4 && *idType < Unicode) { - *id = i; - *idType = Unicode; - } - else if (platform_id == PlatformId_Apple && encoding_id == 0 && language_id == 0 && *idType < Apple) { - *id = i; - *idType = Apple; - } - } - - QString strings[4]; - for (int i = 0; i < 4; ++i) { - if (idStatus[i] == NotFound) - continue; - int id = ids[i]; - quint16 length = qt_getUShort(names + 8 + id * NameRecordSize); - quint16 offset = qt_getUShort(names + 10 + id * NameRecordSize); - const unsigned char *string = table + string_offset + offset; - strings[i] = readName(idStatus[i] != Apple, string, length); - } - - out.name = strings[0]; - out.style = strings[1]; - out.preferredName = strings[2]; - out.preferredStyle = strings[3]; - return out; -} - -} // namespace - -QString qt_getEnglishName(const QString &familyName, bool includeStyle) -{ - QString i18n_name; - QString faceName = familyName; - faceName.truncate(LF_FACESIZE - 1); - - HDC hdc = GetDC( 0 ); - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - faceName.toWCharArray(lf.lfFaceName); - lf.lfFaceName[faceName.size()] = 0; - lf.lfCharSet = DEFAULT_CHARSET; - HFONT hfont = CreateFontIndirect(&lf); - - if (!hfont) { - ReleaseDC(0, hdc); - return QString(); - } - - HGDIOBJ oldobj = SelectObject( hdc, hfont ); - - const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' ); - - // get the name table - unsigned char *table = 0; - - DWORD bytes = GetFontData( hdc, name_tag, 0, 0, 0 ); - if ( bytes == GDI_ERROR ) { - // ### Unused variable - // int err = GetLastError(); - goto error; - } - - table = new unsigned char[bytes]; - GetFontData(hdc, name_tag, 0, table, bytes); - if ( bytes == GDI_ERROR ) - goto error; - - { - const QFontNames names = qt_getCanonicalFontNames(table, bytes); - i18n_name = names.name; - if (includeStyle) - i18n_name += QLatin1Char(' ') + names.style; - } -error: - delete [] table; - SelectObject( hdc, oldobj ); - DeleteObject( hfont ); - ReleaseDC( 0, hdc ); - - //qDebug("got i18n name of '%s' for font '%s'", i18n_name.latin1(), familyName.toLocal8Bit().data()); - return i18n_name; -} - -// Note this duplicates parts of qt_getEnglishName, we should try to unify the two functions. -QFontNames qt_getCanonicalFontNames(const LOGFONT &lf) -{ - QFontNames fontNames; - HDC hdc = GetDC(0); - HFONT hfont = CreateFontIndirect(&lf); - - if (!hfont) { - ReleaseDC(0, hdc); - return fontNames; - } - - HGDIOBJ oldobj = SelectObject(hdc, hfont); - - // get the name table - QByteArray table; - const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e'); - DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0); - if (bytes != GDI_ERROR) { - table.resize(bytes); - - if (GetFontData(hdc, name_tag, 0, table.data(), bytes) != GDI_ERROR) - fontNames = qt_getCanonicalFontNames(reinterpret_cast(table.constData()), bytes); - } - - SelectObject(hdc, oldobj); - DeleteObject(hfont); - ReleaseDC(0, hdc); - - 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.utf16(), sizeof(wchar_t) * nameLength); - faceNamePtr[nameLength] = 0; - } - return faceNamePtr; -} - -namespace { - struct StoreFontPayload { - StoreFontPayload(const QString &family, - QWindowsFontDatabase *fontDatabase) - : populatedFontFamily(family) - , windowsFontDatabase(fontDatabase) - {} - - QString populatedFontFamily; - QSet foundFontAndStyles; - QWindowsFontDatabase *windowsFontDatabase; - }; -} - -static bool addFontToDatabase(QString familyName, - QString styleName, - const LOGFONT &logFont, - const TEXTMETRIC *textmetric, - const FONTSIGNATURE *signature, - int type, - StoreFontPayload *sfp) -{ - // the "@family" fonts are just the same as "family". Ignore them. - if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) - return false; - - uchar charSet = logFont.lfCharSet; - - static const int SMOOTH_SCALABLE = 0xffff; - const QString foundryName; // No such concept. - const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH); - const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); - const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); - const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight; - const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; - const bool antialias = false; - const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight); - const QFont::Stretch stretch = QFont::Unstretched; - -#ifndef QT_NO_DEBUG_OUTPUT - if (lcQpaFonts().isDebugEnabled()) { - QString message; - QTextStream str(&message); - str << __FUNCTION__ << ' ' << familyName << ' ' << charSet << " TTF=" << ttf; - if (type & DEVICE_FONTTYPE) - str << " DEVICE"; - if (type & RASTER_FONTTYPE) - str << " RASTER"; - if (type & TRUETYPE_FONTTYPE) - str << " TRUETYPE"; - str << " scalable=" << scalable << " Size=" << size - << " Style=" << style << " Weight=" << weight - << " stretch=" << stretch; - qCDebug(lcQpaFonts) << message; - } -#endif - QString englishName; - QString faceName; - - QString subFamilyName; - QString subFamilyStyle; - // Look-up names registered in the font - QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); - if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) - englishName = canonicalNames.name; - if (!canonicalNames.preferredName.isEmpty()) { - subFamilyName = familyName; - subFamilyStyle = styleName; - faceName = familyName; // Remember the original name for later lookups - familyName = canonicalNames.preferredName; - styleName = canonicalNames.preferredStyle; - } - - QSupportedWritingSystems writingSystems; - if (type & TRUETYPE_FONTTYPE) { - Q_ASSERT(signature); - quint32 unicodeRange[4] = { - signature->fsUsb[0], signature->fsUsb[1], - signature->fsUsb[2], signature->fsUsb[3] - }; - quint32 codePageRange[2] = { - signature->fsCsb[0], signature->fsCsb[1] - }; - writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains - // the symbol for Baht, and Windows thus reports that it supports the Thai script. - // Since it's the default UI font on this platform, most widgets will be unable to - // display Thai text by default. As a temporary work around, we special case Segoe UI - // and remove the Thai script from its list of supported writing systems. - if (writingSystems.supported(QFontDatabase::Thai) && - familyName == QLatin1String("Segoe UI")) - writingSystems.setSupported(QFontDatabase::Thai, false); - } else { - const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); - if (ws != QFontDatabase::Any) - 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); - } - - QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(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)); - if (style != QFont::StyleItalic && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, - QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(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)); - - if (!subFamilyName.isEmpty() && familyName != subFamilyName) { - QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName)); - } - - if (!englishName.isEmpty() && englishName != familyName) - QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); - - return true; -} - -static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD type, LPARAM lparam) -{ - const ENUMLOGFONTEX *f = reinterpret_cast(logFont); - const QString familyName = QString::fromWCharArray(f->elfLogFont.lfFaceName); - const QString styleName = QString::fromWCharArray(f->elfStyle); - - // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according - // to the documentation is identical to a TEXTMETRIC except for the last four - // members, which we don't use anyway - const FONTSIGNATURE *signature = nullptr; - StoreFontPayload *sfp = reinterpret_cast(lparam); - Q_ASSERT(sfp != nullptr); - if (type & TRUETYPE_FONTTYPE) { - signature = &reinterpret_cast(textmetric)->ntmFontSig; - // We get a callback for each script-type supported, but we register them all - // at once using the signature, so we only need one call to addFontToDatabase(). - FontAndStyle fontAndStyle = {familyName, styleName}; - if (sfp->foundFontAndStyles.contains(fontAndStyle)) - return 1; - sfp->foundFontAndStyles.insert(fontAndStyle); - } - addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp); - - // keep on enumerating - return 1; -} - -void QWindowsFontDatabase::populateFamily(const QString &familyName) -{ - qCDebug(lcQpaFonts) << familyName; - if (familyName.size() >= LF_FACESIZE) { - qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; - return; - } - HDC dummy = GetDC(0); - LOGFONT lf; - lf.lfCharSet = DEFAULT_CHARSET; - familyName.toWCharArray(lf.lfFaceName); - lf.lfFaceName[familyName.size()] = 0; - lf.lfPitchAndFamily = 0; - StoreFontPayload sfp(familyName, this); - EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast(&sfp), 0); - ReleaseDC(0, dummy); -} - -static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD, LPARAM) -{ - // 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); - QPlatformFontDatabase::registerFontFamily(faceName); - // Register current font's english name as alias - const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); - if (ttf && qt_localizedName(faceName)) { - const QString englishName = qt_getEnglishName(faceName); - if (!englishName.isEmpty()) - QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); - } - } - return 1; // continue -} - -void QWindowsFontDatabase::addDefaultEUDCFont() -{ - const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)") - .stringValue(L"SystemDefaultEUDCFont"); - if (!path.isEmpty()) { - QFile file(path); - if (!file.open(QIODevice::ReadOnly)) { - qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << path; - return; - } - - m_eudcFonts = addApplicationFont(file.readAll(), path); - } -} - -void QWindowsFontDatabase::populateFontDatabase() -{ - removeApplicationFonts(); - HDC dummy = GetDC(0); - LOGFONT lf; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfFaceName[0] = 0; - lf.lfPitchAndFamily = 0; - EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0); - ReleaseDC(0, dummy); - // Work around EnumFontFamiliesEx() not listing the system font. - QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family(); - if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily) - QPlatformFontDatabase::registerFontFamily(systemDefaultFamily); - addDefaultEUDCFont(); -} - -QWindowsFontDatabase::QWindowsFontDatabase() -{ - // Properties accessed by QWin32PrintEngine (Qt Print Support) - static const int hfontMetaTypeId = qRegisterMetaType(); - static const int logFontMetaTypeId = qRegisterMetaType(); - Q_UNUSED(hfontMetaTypeId) - Q_UNUSED(logFontMetaTypeId) - - if (lcQpaFonts().isDebugEnabled()) { - QSharedPointer d = data(); - qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: " - << d->clearTypeEnabled << "gamma: " << d->fontSmoothingGamma; - } -} - -QWindowsFontDatabase::~QWindowsFontDatabase() -{ - removeApplicationFonts(); -} - -QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) -{ - const QString faceName(static_cast(handle)); - QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName, - defaultVerticalDPI(), - data()); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle; - return fe; -} - -QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - EmbeddedFont font(fontData); - QFontEngine *fontEngine = 0; - -#if !defined(QT_NO_DIRECTWRITE) - if (!useDirectWrite(hintingPreference)) -#endif - { - GUID guid; - CoCreateGuid(&guid); - -QT_WARNING_PUSH -QT_WARNING_DISABLE_GCC("-Wstrict-aliasing") - QString uniqueFamilyName = QLatin1Char('f') - + QString::number(guid.Data1, 36) + QLatin1Char('-') - + QString::number(guid.Data2, 36) + QLatin1Char('-') - + QString::number(guid.Data3, 36) + QLatin1Char('-') - + QString::number(*reinterpret_cast(guid.Data4), 36); -QT_WARNING_POP - - QString actualFontName = font.changeFamilyName(uniqueFamilyName); - if (actualFontName.isEmpty()) { - qWarning("%s: Can't change family name of font", __FUNCTION__); - return 0; - } - - DWORD count = 0; - QByteArray newFontData = font.data(); - HANDLE fontHandle = - AddFontMemResourceEx(const_cast(newFontData.constData()), - DWORD(newFontData.size()), 0, &count); - if (count == 0 && fontHandle != 0) { - RemoveFontMemResourceEx(fontHandle); - fontHandle = 0; - } - - if (fontHandle == 0) { - qWarning("%s: AddFontMemResourceEx failed", __FUNCTION__); - } else { - QFontDef request; - request.family = uniqueFamilyName; - request.pixelSize = pixelSize; - request.styleStrategy = QFont::PreferMatch; - request.hintingPreference = hintingPreference; - request.stretch = QFont::Unstretched; - - fontEngine = QWindowsFontDatabase::createEngine(request, QString(), - defaultVerticalDPI(), - data()); - - if (fontEngine) { - if (request.family != fontEngine->fontDef.family) { - qWarning("%s: Failed to load font. Got fallback instead: %s", - __FUNCTION__, qPrintable(fontEngine->fontDef.family)); - if (fontEngine->ref.loadRelaxed() == 0) - delete fontEngine; - fontEngine = 0; - } else { - Q_ASSERT(fontEngine->ref.loadRelaxed() == 0); - - // Override the generated font name - switch (fontEngine->type()) { - case QFontEngine::Win: - static_cast(fontEngine)->setUniqueFamilyName(uniqueFamilyName); - fontEngine->fontDef.family = actualFontName; - break; - -#if !defined(QT_NO_DIRECTWRITE) - case QFontEngine::DirectWrite: - static_cast(fontEngine)->setUniqueFamilyName(uniqueFamilyName); - fontEngine->fontDef.family = actualFontName; - break; -#endif // !QT_NO_DIRECTWRITE - - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine."); - } - - UniqueFontData uniqueData; - uniqueData.handle = fontHandle; - uniqueData.refCount.ref(); - m_uniqueFontData[uniqueFamilyName] = uniqueData; - } - } else { - RemoveFontMemResourceEx(fontHandle); - } - } - - // Get style and weight info - if (fontEngine != nullptr) - font.updateFromOS2Table(fontEngine); - } -#if !defined(QT_NO_DIRECTWRITE) - else { - fontEngine = QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference); - } -#endif - - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine; - return fontEngine; -} - -static QList getTrueTypeFontOffsets(const uchar *fontData) -{ - QList offsets; - const quint32 headerTag = *reinterpret_cast(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')) - return offsets; - offsets << 0; - return offsets; - } - const quint32 numFonts = qFromBigEndian(fontData + 8); - for (uint i = 0; i < numFonts; ++i) { - offsets << qFromBigEndian(fontData + 12 + i * 4); - } - return offsets; -} - -static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length) -{ - const quint16 numTables = qFromBigEndian(data + 4); - for (uint i = 0; i < numTables; ++i) { - const quint32 offset = 12 + 16 * i; - if (*reinterpret_cast(data + offset) == tag) { - *table = fileBegin + qFromBigEndian(data + offset + 8); - *length = qFromBigEndian(data + offset + 12); - return; - } - } - *table = 0; - *length = 0; - return; -} - -static void getFamiliesAndSignatures(const QByteArray &fontData, - QList *families, - QVector *signatures, - QVector *values) -{ - const uchar *data = reinterpret_cast(fontData.constData()); - - QList offsets = getTrueTypeFontOffsets(data); - if (offsets.isEmpty()) - return; - - for (int i = 0; i < offsets.count(); ++i) { - const uchar *font = data + offsets.at(i); - const uchar *table; - quint32 length; - getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); - if (!table) - continue; - QFontNames names = qt_getCanonicalFontNames(table, length); - if (names.name.isEmpty()) - continue; - - families->append(std::move(names)); - - if (values || signatures) - getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length); - - if (values) { - QFontValues fontValues; - if (table && length >= 64) { - // Read in some details about the font, offset calculated based on the specification - fontValues.weight = qFromBigEndian(table + 4); - - quint16 fsSelection = qFromBigEndian(table + 62); - fontValues.isItalic = (fsSelection & 1) != 0; - fontValues.isUnderlined = (fsSelection & (1 << 1)) != 0; - fontValues.isOverstruck = (fsSelection & (1 << 4)) != 0; - } - values->append(std::move(fontValues)); - } - - if (signatures) { - FONTSIGNATURE signature; - if (table && length >= 86) { - // Offsets taken from OS/2 table in the TrueType spec - signature.fsUsb[0] = qFromBigEndian(table + 42); - signature.fsUsb[1] = qFromBigEndian(table + 46); - signature.fsUsb[2] = qFromBigEndian(table + 50); - signature.fsUsb[3] = qFromBigEndian(table + 54); - - signature.fsCsb[0] = qFromBigEndian(table + 78); - signature.fsCsb[1] = qFromBigEndian(table + 82); - } else { - memset(&signature, 0, sizeof(signature)); - } - signatures->append(signature); - } - } -} - -QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName, QFontDatabasePrivate::ApplicationFont *applicationFont) -{ - WinApplicationFont font; - font.fileName = fileName; - QVector signatures; - QVector fontValues; - QList families; - QStringList familyNames; - - if (!fontData.isEmpty()) { - getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues); - if (families.isEmpty()) - return familyNames; - - DWORD dummy = 0; - font.handle = - AddFontMemResourceEx(const_cast(fontData.constData()), - DWORD(fontData.size()), 0, &dummy); - if (font.handle == 0) - return QStringList(); - - // Memory fonts won't show up in enumeration, so do add them the hard way. - for (int j = 0; j < families.count(); ++j) { - const auto &family = families.at(j); - const QString &familyName = family.name; - const QString &styleName = family.style; - familyNames << familyName; - HDC hdc = GetDC(0); - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size())); - lf.lfCharSet = DEFAULT_CHARSET; - const QFontValues &values = fontValues.at(j); - lf.lfWeight = values.weight; - if (values.isItalic) - lf.lfItalic = TRUE; - if (values.isOverstruck) - lf.lfStrikeOut = TRUE; - if (values.isUnderlined) - lf.lfUnderline = TRUE; - HFONT hfont = CreateFontIndirect(&lf); - HGDIOBJ oldobj = SelectObject(hdc, hfont); - - if (applicationFont != nullptr) { - QFontDatabasePrivate::ApplicationFont::Properties properties; - properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal; - properties.weight = QPlatformFontDatabase::weightFromInteger(values.weight); - properties.familyName = familyName; - properties.styleName = styleName; - - applicationFont->properties.append(properties); - } - - TEXTMETRIC textMetrics; - GetTextMetrics(hdc, &textMetrics); - - StoreFontPayload sfp(familyName, this); - addFontToDatabase(familyName, styleName, lf, &textMetrics, &signatures.at(j), - TRUETYPE_FONTTYPE, &sfp); - - SelectObject(hdc, oldobj); - DeleteObject(hfont); - ReleaseDC(0, hdc); - } - } else { - QFile f(fileName); - if (!f.open(QIODevice::ReadOnly)) - return QStringList(); - QByteArray data = f.readAll(); - f.close(); - - - getFamiliesAndSignatures(data, &families, nullptr, applicationFont != nullptr ? &fontValues : nullptr); - - if (families.isEmpty()) - return QStringList(); - - if (AddFontResourceExW((wchar_t*)fileName.utf16(), FR_PRIVATE, 0) == 0) - return QStringList(); - - font.handle = 0; - - // Fonts based on files are added via populate, as they will show up in font enumeration. - for (int j = 0; j < families.count(); ++j) { - const QString familyName = families.at(j).name; - familyNames << familyName; - - if (applicationFont != nullptr) { - const QString &styleName = families.at(j).style; - const QFontValues &values = fontValues.at(j); - - QFontDatabasePrivate::ApplicationFont::Properties properties; - properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal; - properties.weight = QPlatformFontDatabase::weightFromInteger(values.weight); - properties.familyName = familyName; - properties.styleName = styleName; - - applicationFont->properties.append(properties); - } - - populateFamily(familyName); - } - } - - m_applicationFonts << font; - - return familyNames; -} - -void QWindowsFontDatabase::removeApplicationFonts() -{ - for (const WinApplicationFont &font : qAsConst(m_applicationFonts)) { - if (font.handle) { - RemoveFontMemResourceEx(font.handle); - } else { - RemoveFontResourceExW(reinterpret_cast(font.fileName.utf16()), - FR_PRIVATE, nullptr); - } - } - m_applicationFonts.clear(); - m_eudcFonts.clear(); -} - -void QWindowsFontDatabase::releaseHandle(void *handle) -{ - const QChar *faceName = reinterpret_cast(handle); - delete[] faceName; -} - -QString QWindowsFontDatabase::fontDir() const -{ - const QString result = QPlatformFontDatabase::fontDir(); - qCDebug(lcQpaFonts) << __FUNCTION__ << result; - return result; -} - -bool QWindowsFontDatabase::fontsAlwaysScalable() const -{ - return false; -} - -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); - } - } -} - -void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont) -{ - if (m_uniqueFontData.contains(uniqueFont)) - m_uniqueFontData[uniqueFont].refCount.ref(); -} - -QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - QStringList result; - result.append(familyForStyleHint(styleHint)); - result.append(m_eudcFonts); - result.append(extraTryFontsForFamily(family)); - result.append(QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script)); - - qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint - << script << result; - return result; -} - - -QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const QString &faceName, - int dpi, - const QSharedPointer &data) -{ - QFontEngine *fe = 0; - - LOGFONT lf = fontDefToLOGFONT(request, faceName); - const bool preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY; - - if (request.stretch != 100) { - HFONT hfont = CreateFontIndirect(&lf); - if (!hfont) { - qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); - hfont = QWindowsFontDatabase::systemFont(); - } - - HGDIOBJ oldObj = SelectObject(data->hdc, hfont); - TEXTMETRIC tm; - if (!GetTextMetrics(data->hdc, &tm)) - qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__); - else - lf.lfWidth = tm.tmAveCharWidth * request.stretch / 100; - SelectObject(data->hdc, oldObj); - - DeleteObject(hfont); - } - -#if !defined(QT_NO_DIRECTWRITE) - if (data->directWriteFactory != nullptr) { - const QString fam = QString::fromWCharArray(lf.lfFaceName); - const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam); - if (nameSubstitute != fam) { - const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1); - memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t)); - lf.lfFaceName[nameSubstituteLength] = 0; - } - - HFONT hfont = CreateFontIndirect(&lf); - if (!hfont) { - qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__); - } else { - HGDIOBJ oldFont = SelectObject(data->hdc, hfont); - - const QFont::HintingPreference hintingPreference = - static_cast(request.hintingPreference); - bool useDw = useDirectWrite(hintingPreference, fam); - - IDWriteFontFace *directWriteFontFace = NULL; - HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace); - if (SUCCEEDED(hr)) { - bool isColorFont = false; -#if defined(QT_USE_DIRECTWRITE2) - IDWriteFontFace2 *directWriteFontFace2 = nullptr; - if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2), - reinterpret_cast(&directWriteFontFace2)))) { - if (directWriteFontFace2->IsColorFont()) - isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0; - - directWriteFontFace2->Release(); - } -#endif - useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont); - qCDebug(lcQpaFonts) << __FUNCTION__ << request.family << request.pointSize - << "pt" << "hintingPreference=" << hintingPreference << "color=" << isColorFont - << dpi << "dpi" << "useDirectWrite=" << useDw; - if (useDw) { - QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, - request.pixelSize, - data); - - wchar_t n[64]; - GetTextFace(data->hdc, 64, n); - - QFontDef fontDef = request; - fontDef.family = QString::fromWCharArray(n); - - if (isColorFont) - fedw->glyphFormat = QFontEngine::Format_ARGB; - fedw->initFontInfo(fontDef, dpi); - fe = fedw; - } - directWriteFontFace->Release(); - } else if (useDw) { - const QString errorString = qt_error_string(int(hr)); - qWarning().noquote().nospace() << "DirectWrite: CreateFontFaceFromHDC() failed (" - << errorString << ") for " << request << ' ' << lf << " dpi=" << dpi; - } - - SelectObject(data->hdc, oldFont); - DeleteObject(hfont); - } - } -#endif // QT_NO_DIRECTWRITE - - if (!fe) { - QWindowsFontEngine *few = new QWindowsFontEngine(request.family, lf, data); - if (preferClearTypeAA) - few->glyphFormat = QFontEngine::Format_A32; - few->initFontInfo(request, dpi); - fe = few; - } - - return fe; -} - -bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const -{ - return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp deleted file mode 100644 index cde20eebc2..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -#include "qwindowsfontdatabase_ft_p.h" -#include "qwindowsfontdatabase_p.h" - -#include - -#include -#include FT_TRUETYPE_TABLES_H - -#include -#include -#include -#if QT_CONFIG(regularexpression) -#include -#endif -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSet) -{ - switch (charSet) { - case ANSI_CHARSET: - case EASTEUROPE_CHARSET: - case BALTIC_CHARSET: - case TURKISH_CHARSET: - return QFontDatabase::Latin; - case GREEK_CHARSET: - return QFontDatabase::Greek; - case RUSSIAN_CHARSET: - return QFontDatabase::Cyrillic; - case HEBREW_CHARSET: - return QFontDatabase::Hebrew; - case ARABIC_CHARSET: - return QFontDatabase::Arabic; - case THAI_CHARSET: - return QFontDatabase::Thai; - case GB2312_CHARSET: - return QFontDatabase::SimplifiedChinese; - case CHINESEBIG5_CHARSET: - return QFontDatabase::TraditionalChinese; - case SHIFTJIS_CHARSET: - return QFontDatabase::Japanese; - case HANGUL_CHARSET: - case JOHAB_CHARSET: - return QFontDatabase::Korean; - case VIETNAMESE_CHARSET: - return QFontDatabase::Vietnamese; - case SYMBOL_CHARSET: - return QFontDatabase::Symbol; - default: - break; - } - return QFontDatabase::Any; -} - -static FontFile * createFontFile(const QString &fileName, int index) -{ - FontFile *fontFile = new FontFile; - fontFile->fileName = fileName; - fontFile->indexValue = index; - return fontFile; -} - -namespace { -struct FontKey -{ - QString fileName; - QStringList fontNames; -}; -} // namespace - -typedef QVector FontKeys; - -static FontKeys &fontKeys() -{ - static FontKeys result; - if (result.isEmpty()) { - const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), - QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") }; - for (const auto key : keys) { - const QSettings fontRegistry(key, QSettings::NativeFormat); - const QStringList allKeys = fontRegistry.allKeys(); - const QString trueType = QStringLiteral("(TrueType)"); -#if QT_CONFIG(regularexpression) - const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+")); - Q_ASSERT(sizeListMatch.isValid()); -#endif - const int size = allKeys.size(); - result.reserve(result.size() + size); - for (int i = 0; i < size; ++i) { - FontKey fontKey; - const QString ®istryFontKey = allKeys.at(i); - fontKey.fileName = fontRegistry.value(registryFontKey).toString(); - QString realKey = registryFontKey; - realKey.remove(trueType); -#if QT_CONFIG(regularexpression) - realKey.remove(sizeListMatch); -#endif - const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&')); - fontKey.fontNames.reserve(fontNames.size()); - for (const QStringRef &fontName : fontNames) - fontKey.fontNames.append(fontName.trimmed().toString()); - result.append(fontKey); - } - } - } - return result; -} - -static const FontKey *findFontKey(const QString &name, int *indexIn = nullptr) -{ - const FontKeys &keys = fontKeys(); - for (auto it = keys.constBegin(), cend = keys.constEnd(); it != cend; ++it) { - const int index = it->fontNames.indexOf(name); - if (index >= 0) { - if (indexIn) - *indexIn = index; - return &(*it); - } - } - if (indexIn) - *indexIn = -1; - return nullptr; -} - -static bool addFontToDatabase(QString familyName, - QString styleName, - const QString &fullName, - const LOGFONT &logFont, - const TEXTMETRIC *textmetric, - const FONTSIGNATURE *signature, - int type) -{ - // the "@family" fonts are just the same as "family". Ignore them. - if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_"))) - return false; - - uchar charSet = logFont.lfCharSet; - - static const int SMOOTH_SCALABLE = 0xffff; - const QString foundryName; // No such concept. - const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH); - const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE); - const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE); - const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight; - const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal; - const bool antialias = false; - const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight); - const QFont::Stretch stretch = QFont::Unstretched; - -#ifndef QT_NO_DEBUG_STREAM - if (lcQpaFonts().isDebugEnabled()) { - QString message; - QTextStream str(&message); - str << __FUNCTION__ << ' ' << familyName << "::" << fullName << ' ' << charSet << " TTF=" << ttf; - if (type & DEVICE_FONTTYPE) - str << " DEVICE"; - if (type & RASTER_FONTTYPE) - str << " RASTER"; - if (type & TRUETYPE_FONTTYPE) - str << " TRUETYPE"; - str << " scalable=" << scalable << " Size=" << size - << " Style=" << style << " Weight=" << weight - << " stretch=" << stretch; - qCDebug(lcQpaFonts) << message; - } -#endif - - QString englishName; - QString faceName = familyName; - - QString subFamilyName; - QString subFamilyStyle; - // Look-up names registered in the font - QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); - if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) - englishName = canonicalNames.name; - if (!canonicalNames.preferredName.isEmpty()) { - subFamilyName = familyName; - subFamilyStyle = styleName; - familyName = canonicalNames.preferredName; - styleName = canonicalNames.preferredStyle; - } - - QSupportedWritingSystems writingSystems; - if (type & TRUETYPE_FONTTYPE) { - Q_ASSERT(signature); - quint32 unicodeRange[4] = { - signature->fsUsb[0], signature->fsUsb[1], - signature->fsUsb[2], signature->fsUsb[3] - }; - quint32 codePageRange[2] = { - signature->fsCsb[0], signature->fsCsb[1] - }; - writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - // ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains - // the symbol for Baht, and Windows thus reports that it supports the Thai script. - // Since it's the default UI font on this platform, most widgets will be unable to - // display Thai text by default. As a temporary work around, we special case Segoe UI - // and remove the Thai script from its list of supported writing systems. - if (writingSystems.supported(QFontDatabase::Thai) && - faceName == QLatin1String("Segoe UI")) - writingSystems.setSupported(QFontDatabase::Thai, false); - } else { - const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet); - if (ws != QFontDatabase::Any) - writingSystems.setSupported(ws); - } - - int index = 0; - const FontKey *key = findFontKey(fullName, &index); - if (!key) { - // On non-English locales, the styles of the font may be localized in enumeration, but - // not in the registry. - QLocale systemLocale = QLocale::system(); - if (systemLocale.language() != QLocale::C - && systemLocale.language() != QLocale::English - && styleName != QLatin1String("Italic") - && styleName != QLatin1String("Bold")) { - key = findFontKey(qt_getEnglishName(fullName, true), &index); - } - if (!key) - key = findFontKey(faceName, &index); - if (!key && !englishName.isEmpty()) - key = findFontKey(englishName, &index); - if (!key) - return false; - } - QString value = key->fileName; - if (value.isEmpty()) - return false; - - if (!QDir::isAbsolutePath(value)) - value.prepend(QFile::decodeName(qgetenv("windir") + "\\Fonts\\")); - - QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight, style, stretch, - antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - - // 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(value, index)); - - if (style != QFont::StyleItalic && styleName.isEmpty()) - QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight, QFont::StyleItalic, stretch, - antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - - 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(value, index)); - - if (!subFamilyName.isEmpty() && familyName != subFamilyName) { - QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight, - style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(value, index)); - } - - if (!englishName.isEmpty() && englishName != familyName) - QPlatformFontDatabase::registerAliasToFontFamily(familyName, englishName); - - return true; -} - -static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD type, LPARAM lparam) -{ - const ENUMLOGFONTEX *f = reinterpret_cast(logFont); - const QString faceName = QString::fromWCharArray(f->elfLogFont.lfFaceName); - const QString styleName = QString::fromWCharArray(f->elfStyle); - const QString fullName = QString::fromWCharArray(f->elfFullName); - - // NEWTEXTMETRICEX (passed for TT fonts) is a NEWTEXTMETRIC, which according - // to the documentation is identical to a TEXTMETRIC except for the last four - // members, which we don't use anyway - const FONTSIGNATURE *signature = nullptr; - if (type & TRUETYPE_FONTTYPE) { - signature = &reinterpret_cast(textmetric)->ntmFontSig; - // We get a callback for each script-type supported, but we register them all - // at once using the signature, so we only need one call to addFontToDatabase(). - QSet *foundFontAndStyles = reinterpret_cast *>(lparam); - FontAndStyle fontAndStyle = {faceName, styleName}; - if (foundFontAndStyles->contains(fontAndStyle)) - return 1; - foundFontAndStyles->insert(fontAndStyle); - } - addFontToDatabase(faceName, styleName, fullName, *logFont, textmetric, signature, type); - - // keep on enumerating - return 1; -} - -/*! - \brief Populate font database using EnumFontFamiliesEx(). - - Normally, leaving the name empty should enumerate - all fonts, however, system fonts like "MS Shell Dlg 2" - are only found when specifying the name explicitly. -*/ - -void QWindowsFontDatabaseFT::populateFamily(const QString &familyName) -{ - qCDebug(lcQpaFonts) << familyName; - if (familyName.size() >= LF_FACESIZE) { - qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\''; - return; - } - HDC dummy = GetDC(0); - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - familyName.toWCharArray(lf.lfFaceName); - lf.lfFaceName[familyName.size()] = 0; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfPitchAndFamily = 0; - QSet foundFontAndStyles; - EnumFontFamiliesEx(dummy, &lf, storeFont, reinterpret_cast(&foundFontAndStyles), 0); - ReleaseDC(0, dummy); -} - -// Delayed population of font families - -static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TEXTMETRIC *textmetric, - DWORD, LPARAM) -{ - const ENUMLOGFONTEX *f = reinterpret_cast(logFont); - // the "@family" fonts are just the same as "family". Ignore them. - const wchar_t *faceNameW = f->elfLogFont.lfFaceName; - if (faceNameW[0] && faceNameW[0] != L'@' && wcsncmp(faceNameW, L"WST_", 4)) { - // Register only font families for which a font file exists for delayed population - const bool ttf = textmetric->tmPitchAndFamily & TMPF_TRUETYPE; - const QString faceName = QString::fromWCharArray(faceNameW); - const FontKey *key = findFontKey(faceName); - if (!key) { - key = findFontKey(QString::fromWCharArray(f->elfFullName)); - if (!key && ttf && qt_localizedName(faceName)) - key = findFontKey(qt_getEnglishName(faceName)); - } - if (key) { - QPlatformFontDatabase::registerFontFamily(faceName); - // Register current font's english name as alias - if (ttf && qt_localizedName(faceName)) { - const QString englishName = qt_getEnglishName(faceName); - if (!englishName.isEmpty()) - QPlatformFontDatabase::registerAliasToFontFamily(faceName, englishName); - } - } - } - return 1; // continue -} - -void QWindowsFontDatabaseFT::populateFontDatabase() -{ - HDC dummy = GetDC(0); - LOGFONT lf; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfFaceName[0] = 0; - lf.lfPitchAndFamily = 0; - EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0); - ReleaseDC(0, dummy); - // Work around EnumFontFamiliesEx() not listing the system font - QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family(); - if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily) - QPlatformFontDatabase::registerFontFamily(systemDefaultFamily); -} - -QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, void *handle) -{ - QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontDef, handle); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef.family << fe << handle; - return fe; -} - -QFontEngine *QWindowsFontDatabaseFT::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - QFontEngine *fe = QFreeTypeFontDatabase::fontEngine(fontData, pixelSize, hintingPreference); - qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fe; - return fe; -} - -QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const -{ - QStringList result; - result.append(QWindowsFontDatabaseBase::familyForStyleHint(styleHint)); - result.append(QWindowsFontDatabaseBase::extraTryFontsForFamily(family)); - result.append(QFreeTypeFontDatabase::fallbacksForFamily(family, style, styleHint, script)); - - qCDebug(lcQpaFonts) << __FUNCTION__ << family << style << styleHint - << script << result; - - return result; -} -QString QWindowsFontDatabaseFT::fontDir() const -{ - const QString result = QLatin1String(qgetenv("windir")) + QLatin1String("/Fonts");//QPlatformFontDatabase::fontDir(); - qCDebug(lcQpaFonts) << __FUNCTION__ << result; - return result; -} - -QFont QWindowsFontDatabaseFT::defaultFont() const -{ - return QWindowsFontDatabase::systemDefaultFont(); -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h deleted file mode 100644 index 16f61010d4..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft_p.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTDATABASEFT_H -#define QWINDOWSFONTDATABASEFT_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QWindowsFontDatabaseFT : public QFreeTypeFontDatabase -{ -public: - void populateFontDatabase() override; - void populateFamily(const QString &familyName) 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; - - QString fontDir() const override; - QFont defaultFont() const override; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSFONTDATABASEFT_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h deleted file mode 100644 index 0652685fc5..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTDATABASE_H -#define QWINDOWSFONTDATABASE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qwindowsfontdatabasebase_p.h" - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QWindowsFontDatabase : public QWindowsFontDatabaseBase -{ - Q_DISABLE_COPY_MOVE(QWindowsFontDatabase) -public: - enum FontOptions { - // Relevant bits from QWindowsIntegration::Options - DontUseDirectWriteFonts = 0x40, - DontUseColorFonts = 0x80 - }; - - QWindowsFontDatabase(); - ~QWindowsFontDatabase() override; - - void ensureFamilyPopulated(const QString &familyName); - - void populateFontDatabase() override; - void populateFamily(const QString &familyName) 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 *applicationFont = nullptr) override; - void releaseHandle(void *handle) override; - QString fontDir() const override; - - QFont defaultFont() const override { return systemDefaultFont(); } - bool fontsAlwaysScalable() const override; - void derefUniqueFont(const QString &uniqueFont); - void refUniqueFont(const QString &uniqueFont); - bool isPrivateFontFamily(const QString &family) const override; - - static QFontEngine *createEngine(const QFontDef &request, const QString &faceName, - int dpi, - const QSharedPointer &data); - - static qreal fontSmoothingGamma(); - - static void setFontOptions(unsigned options); - static unsigned fontOptions(); - -private: - void removeApplicationFonts(); - void addDefaultEUDCFont(); - - struct WinApplicationFont { - HANDLE handle; - QString fileName; - }; - - QList m_applicationFonts; - - struct UniqueFontData { - HANDLE handle; - QAtomicInt refCount; - }; - - QMap m_uniqueFontData; - - static unsigned m_fontOptions; - QStringList m_eudcFonts; -}; - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug, const QFontDef &def); -#endif - -inline quint16 qt_getUShort(const unsigned char *p) -{ - quint16 val; - val = *p++ << 8; - val |= *p; - - return val; -} - -struct QFontNames -{ - QString name; // e.g. "DejaVu Sans Condensed" - QString style; // e.g. "Italic" - QString preferredName; // e.g. "DejaVu Sans" - QString preferredStyle; // e.g. "Condensed Italic" -}; - -struct QFontValues -{ - quint16 weight = 0; - bool isItalic = false; - bool isOverstruck = false; - bool isUnderlined = false; -}; - -bool qt_localizedName(const QString &name); -QString qt_getEnglishName(const QString &familyName, bool includeStyle = false); -QFontNames qt_getCanonicalFontNames(const LOGFONT &lf); - -struct FontAndStyle { - QString font; - QString style; - - friend inline bool operator==(const FontAndStyle &lhs, const FontAndStyle &rhs) noexcept - { return lhs.font == rhs.font && lhs.style == rhs.style; } - friend inline bool operator!=(const FontAndStyle &lhs, const FontAndStyle &rhs) noexcept - { return !operator==(lhs, rhs); } -}; -inline size_t qHash(const FontAndStyle &key, size_t seed) noexcept -{ - return qHashMulti(seed, key.font, key.style); -} - -QT_END_NAMESPACE - -#endif // QWINDOWSFONTDATABASE_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp deleted file mode 100644 index 568d1463e7..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp +++ /dev/null @@ -1,985 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#include "qwindowsfontdatabasebase_p.h" -#include "qwindowsfontdatabase_p.h" - -#include -#include -#include - -#if !defined(QT_NO_DIRECTWRITE) -# if defined(QT_USE_DIRECTWRITE3) -# include -# elif defined(QT_USE_DIRECTWRITE2) -# include -# else -# include -# endif -# include -# include "qwindowsfontenginedirectwrite_p.h" -#endif - -QT_BEGIN_NAMESPACE - -// Helper classes for creating font engines directly from font data -namespace { - -# pragma pack(1) - - // Common structure for all formats of the "name" table - struct NameTable - { - quint16 format; - quint16 count; - quint16 stringOffset; - }; - - struct NameRecord - { - quint16 platformID; - quint16 encodingID; - quint16 languageID; - quint16 nameID; - quint16 length; - quint16 offset; - }; - - struct OffsetSubTable - { - quint32 scalerType; - quint16 numTables; - quint16 searchRange; - quint16 entrySelector; - quint16 rangeShift; - }; - - struct TableDirectory : public QWindowsFontDatabaseBase::FontTable - { - quint32 identifier; - quint32 checkSum; - quint32 offset; - quint32 length; - }; - - struct OS2Table - { - quint16 version; - qint16 avgCharWidth; - quint16 weightClass; - quint16 widthClass; - quint16 type; - qint16 subscriptXSize; - qint16 subscriptYSize; - qint16 subscriptXOffset; - qint16 subscriptYOffset; - qint16 superscriptXSize; - qint16 superscriptYSize; - qint16 superscriptXOffset; - qint16 superscriptYOffset; - qint16 strikeOutSize; - qint16 strikeOutPosition; - qint16 familyClass; - quint8 panose[10]; - quint32 unicodeRanges[4]; - quint8 vendorID[4]; - quint16 selection; - quint16 firstCharIndex; - quint16 lastCharIndex; - qint16 typoAscender; - qint16 typoDescender; - qint16 typoLineGap; - quint16 winAscent; - quint16 winDescent; - quint32 codepageRanges[2]; - qint16 height; - qint16 capHeight; - quint16 defaultChar; - quint16 breakChar; - quint16 maxContext; - }; - -# pragma pack() - -} // Anonymous namespace - -QWindowsFontDatabaseBase::FontTable *QWindowsFontDatabaseBase::EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName) -{ - Q_ASSERT(tagName.size() == 4); - quint32 tagId = *(reinterpret_cast(tagName.constData())); - const size_t fontDataSize = m_fontData.size(); - if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable))) - return nullptr; - - OffsetSubTable *offsetSubTable = reinterpret_cast(m_fontData.data()); - TableDirectory *tableDirectory = reinterpret_cast(offsetSubTable + 1); - - const size_t tableCount = qFromBigEndian(offsetSubTable->numTables); - if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount)) - return nullptr; - - TableDirectory *tableDirectoryEnd = tableDirectory + tableCount; - for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) { - if (entry->identifier == tagId) - return entry; - } - - return nullptr; -} - -QString QWindowsFontDatabaseBase::EmbeddedFont::familyName(QWindowsFontDatabaseBase::FontTable *directoryEntry) -{ - QString name; - - TableDirectory *nameTableDirectoryEntry = static_cast(directoryEntry); - if (nameTableDirectoryEntry == nullptr) - nameTableDirectoryEntry = static_cast(tableDirectoryEntry("name")); - - if (nameTableDirectoryEntry != nullptr) { - quint32 offset = qFromBigEndian(nameTableDirectoryEntry->offset); - if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable))) - return QString(); - - NameTable *nameTable = reinterpret_cast(m_fontData.data() + offset); - NameRecord *nameRecord = reinterpret_cast(nameTable + 1); - - quint16 nameTableCount = qFromBigEndian(nameTable->count); - if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount)) - return QString(); - - for (int i = 0; i < nameTableCount; ++i, ++nameRecord) { - if (qFromBigEndian(nameRecord->nameID) == 1 - && qFromBigEndian(nameRecord->platformID) == 3 // Windows - && qFromBigEndian(nameRecord->languageID) == 0x0409) { // US English - quint16 stringOffset = qFromBigEndian(nameTable->stringOffset); - quint16 nameOffset = qFromBigEndian(nameRecord->offset); - quint16 nameLength = qFromBigEndian(nameRecord->length); - - if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength)) - return QString(); - - const void *ptr = reinterpret_cast(nameTable) - + stringOffset - + nameOffset; - - const quint16 *s = reinterpret_cast(ptr); - const quint16 *e = s + nameLength / sizeof(quint16); - while (s != e) - name += QChar( qFromBigEndian(*s++)); - break; - } - } - } - - return name; -} - -void QWindowsFontDatabaseBase::EmbeddedFont::updateFromOS2Table(QFontEngine *fontEngine) -{ - TableDirectory *os2TableEntry = static_cast(tableDirectoryEntry("OS/2")); - if (os2TableEntry != nullptr) { - const OS2Table *os2Table = - reinterpret_cast(m_fontData.constData() - + qFromBigEndian(os2TableEntry->offset)); - - bool italic = qFromBigEndian(os2Table->selection) & (1 << 0); - bool oblique = qFromBigEndian(os2Table->selection) & (1 << 9); - - if (italic) - fontEngine->fontDef.style = QFont::StyleItalic; - else if (oblique) - fontEngine->fontDef.style = QFont::StyleOblique; - else - fontEngine->fontDef.style = QFont::StyleNormal; - - fontEngine->fontDef.weight = QPlatformFontDatabase::weightFromInteger(qFromBigEndian(os2Table->weightClass)); - } -} - -QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(const QString &newFamilyName) -{ - TableDirectory *nameTableDirectoryEntry = static_cast(tableDirectoryEntry("name")); - if (nameTableDirectoryEntry == nullptr) - return QString(); - - QString oldFamilyName = familyName(nameTableDirectoryEntry); - - // Reserve size for name table header, five required name records and string - const int requiredRecordCount = 5; - quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 }; - - int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount; - int newFamilyNameSize = newFamilyName.size() * int(sizeof(quint16)); - - const QString regularString = QString::fromLatin1("Regular"); - int regularStringSize = regularString.size() * int(sizeof(quint16)); - - // Align table size of table to 32 bits (pad with 0) - int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4; - - QByteArray newNameTable(fullSize, char(0)); - - { - NameTable *nameTable = reinterpret_cast(newNameTable.data()); - nameTable->count = qbswap(requiredRecordCount); - nameTable->stringOffset = qbswap(sizeOfHeader); - - NameRecord *nameRecord = reinterpret_cast(nameTable + 1); - for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) { - nameRecord->nameID = qbswap(nameIds[i]); - nameRecord->encodingID = qbswap(1); - nameRecord->languageID = qbswap(0x0409); - nameRecord->platformID = qbswap(3); - nameRecord->length = qbswap(newFamilyNameSize); - - // Special case for sub-family - if (nameIds[i] == 4) { - nameRecord->offset = qbswap(newFamilyNameSize); - nameRecord->length = qbswap(regularStringSize); - } - } - - // nameRecord now points to string data - quint16 *stringStorage = reinterpret_cast(nameRecord); - const quint16 *sourceString = newFamilyName.utf16(); - for (int i = 0; i < newFamilyName.size(); ++i) - stringStorage[i] = qbswap(sourceString[i]); - stringStorage += newFamilyName.size(); - - sourceString = regularString.utf16(); - for (int i = 0; i < regularString.size(); ++i) - stringStorage[i] = qbswap(sourceString[i]); - } - - quint32 *p = reinterpret_cast(newNameTable.data()); - quint32 *tableEnd = reinterpret_cast(newNameTable.data() + fullSize); - - quint32 checkSum = 0; - while (p < tableEnd) - checkSum += qFromBigEndian(*(p++)); - - nameTableDirectoryEntry->checkSum = qbswap(checkSum); - nameTableDirectoryEntry->offset = qbswap(m_fontData.size()); - nameTableDirectoryEntry->length = qbswap(fullSize); - - m_fontData.append(newNameTable); - - return oldFamilyName; -} - -#if !defined(QT_NO_DIRECTWRITE) - -namespace { - class DirectWriteFontFileStream: public IDWriteFontFileStream - { - Q_DISABLE_COPY(DirectWriteFontFileStream) - public: - DirectWriteFontFileStream(const QByteArray &fontData) - : m_fontData(fontData) - , m_referenceCount(0) - { - } - virtual ~DirectWriteFontFileStream() - { - } - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset, - UINT64 fragmentSize, OUT void **fragmentContext); - void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext); - HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize); - HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime); - - private: - QByteArray m_fontData; - ULONG m_referenceCount; - }; - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object) - { - if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { - *object = this; - AddRef(); - return S_OK; - } else { - *object = NULL; - return E_NOINTERFACE; - } - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef() - { - return InterlockedIncrement(&m_referenceCount); - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release() - { - ULONG newCount = InterlockedDecrement(&m_referenceCount); - if (newCount == 0) - delete this; - return newCount; - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment( - const void **fragmentStart, - UINT64 fileOffset, - UINT64 fragmentSize, - OUT void **fragmentContext) - { - *fragmentContext = NULL; - if (fileOffset + fragmentSize <= quint64(m_fontData.size())) { - *fragmentStart = m_fontData.data() + fileOffset; - return S_OK; - } else { - *fragmentStart = NULL; - return E_FAIL; - } - } - - void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *) - { - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize) - { - *fileSize = m_fontData.size(); - return S_OK; - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) - { - *lastWriteTime = 0; - return E_NOTIMPL; - } - - class DirectWriteFontFileLoader: public IDWriteFontFileLoader - { - public: - DirectWriteFontFileLoader() : m_referenceCount(0) {} - virtual ~DirectWriteFontFileLoader() - { - } - - inline void addKey(const void *key, const QByteArray &fontData) - { - Q_ASSERT(!m_fontDatas.contains(key)); - m_fontDatas.insert(key, fontData); - } - - inline void removeKey(const void *key) - { - m_fontDatas.remove(key); - } - - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); - ULONG STDMETHODCALLTYPE AddRef(); - ULONG STDMETHODCALLTYPE Release(); - - HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey, - UINT32 fontFileReferenceKeySize, - OUT IDWriteFontFileStream **fontFileStream); - - private: - ULONG m_referenceCount; - QHash m_fontDatas; - }; - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, - void **object) - { - if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { - *object = this; - AddRef(); - return S_OK; - } else { - *object = NULL; - return E_NOINTERFACE; - } - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef() - { - return InterlockedIncrement(&m_referenceCount); - } - - ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release() - { - ULONG newCount = InterlockedDecrement(&m_referenceCount); - if (newCount == 0) - delete this; - return newCount; - } - - HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey( - void const *fontFileReferenceKey, - UINT32 fontFileReferenceKeySize, - IDWriteFontFileStream **fontFileStream) - { - Q_UNUSED(fontFileReferenceKeySize); - - if (fontFileReferenceKeySize != sizeof(const void *)) { - qWarning("%s: Wrong key size", __FUNCTION__); - return E_FAIL; - } - - const void *key = *reinterpret_cast(fontFileReferenceKey); - *fontFileStream = NULL; - auto it = m_fontDatas.constFind(key); - if (it == m_fontDatas.constEnd()) - return E_FAIL; - - QByteArray fontData = it.value(); - DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); - stream->AddRef(); - *fontFileStream = stream; - - return S_OK; - } - - class CustomFontFileLoader - { - public: - CustomFontFileLoader(IDWriteFactory *factory) - { - m_directWriteFactory = factory; - - if (m_directWriteFactory) { - m_directWriteFactory->AddRef(); - - m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); - m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); - } - } - - ~CustomFontFileLoader() - { - if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr) - m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader); - - if (m_directWriteFactory != nullptr) - m_directWriteFactory->Release(); - } - - void addKey(const void *key, const QByteArray &fontData) - { - if (m_directWriteFontFileLoader != nullptr) - m_directWriteFontFileLoader->addKey(key, fontData); - } - - void removeKey(const void *key) - { - if (m_directWriteFontFileLoader != nullptr) - m_directWriteFontFileLoader->removeKey(key); - } - - IDWriteFontFileLoader *loader() const - { - return m_directWriteFontFileLoader; - } - - private: - IDWriteFactory *m_directWriteFactory = nullptr; - DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr; - }; -} // Anonymous namespace - -#endif // !defined(QT_NO_DIRECTWRITE) - - -QWindowsFontEngineData::~QWindowsFontEngineData() -{ - if (hdc) - DeleteDC(hdc); - -#if !defined(QT_NO_DIRECTWRITE) - if (directWriteGdiInterop) - directWriteGdiInterop->Release(); - if (directWriteFactory) - directWriteFactory->Release(); -#endif -} - -QWindowsFontDatabaseBase::QWindowsFontDatabaseBase() -{ -} - -QWindowsFontDatabaseBase::~QWindowsFontDatabaseBase() -{ -} - -typedef QSharedPointer QWindowsFontEngineDataPtr; -typedef QThreadStorage FontEngineThreadLocalData; -Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData) - -QSharedPointer QWindowsFontDatabaseBase::data() -{ - FontEngineThreadLocalData *data = fontEngineThreadLocalData(); - if (!data->hasLocalData()) - data->setLocalData(QSharedPointer::create()); - - if (!init(data->localData())) - qCWarning(lcQpaFonts) << "Cannot initialize common font database data"; - - return data->localData(); -} - -bool QWindowsFontDatabaseBase::init(QSharedPointer d) -{ -#if !defined(QT_NO_DIRECTWRITE) - if (!d->directWriteFactory) { - createDirectWriteFactory(&d->directWriteFactory); - if (!d->directWriteFactory) - return false; - } - if (!d->directWriteGdiInterop) { - const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop); - if (FAILED(hr)) { - qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__); - return false; - } - } -#endif - return true; -} - -#if !defined(QT_NO_DIRECTWRITE) -// ### 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(result); -} - -void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory) -{ - *factory = nullptr; - - static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory(); - if (!dWriteCreateFactory) - return; - - IUnknown *result = nullptr; -# if defined(QT_USE_DIRECTWRITE3) - dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result); -# endif - -# if defined(QT_USE_DIRECTWRITE2) - if (result == nullptr) - dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result); -# endif - - if (result == nullptr) { - if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) { - qErrnoWarning("DWriteCreateFactory failed"); - return; - } - } - - *factory = static_cast(result); -} -#endif // !defined(QT_NO_DIRECTWRITE) - -static int s_defaultVerticalDPI = 96; // Native Pixels - -int QWindowsFontDatabaseBase::defaultVerticalDPI() -{ - return s_defaultVerticalDPI; -} - -void QWindowsFontDatabaseBase::setDefaultVerticalDPI(int d) -{ - s_defaultVerticalDPI = d; -} - -LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName) -{ - LOGFONT lf; - memset(&lf, 0, sizeof(LOGFONT)); - - lf.lfHeight = -qRound(request.pixelSize); - lf.lfWidth = 0; - lf.lfEscapement = 0; - lf.lfOrientation = 0; - if (request.weight == 50) - lf.lfWeight = FW_DONTCARE; - else - lf.lfWeight = (request.weight*900)/99; - lf.lfItalic = request.style != QFont::StyleNormal; - lf.lfCharSet = DEFAULT_CHARSET; - - int strat = OUT_DEFAULT_PRECIS; - if (request.styleStrategy & QFont::PreferBitmap) { - strat = OUT_RASTER_PRECIS; - } else if (request.styleStrategy & QFont::PreferDevice) { - strat = OUT_DEVICE_PRECIS; - } else if (request.styleStrategy & QFont::PreferOutline) { - strat = OUT_OUTLINE_PRECIS; - } else if (request.styleStrategy & QFont::ForceOutline) { - strat = OUT_TT_ONLY_PRECIS; - } - - lf.lfOutPrecision = strat; - - int qual = DEFAULT_QUALITY; - - if (request.styleStrategy & QFont::PreferMatch) - qual = DRAFT_QUALITY; - else if (request.styleStrategy & QFont::PreferQuality) - qual = PROOF_QUALITY; - - if (request.styleStrategy & QFont::PreferAntialias) { - qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0 - ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY; - } else if (request.styleStrategy & QFont::NoAntialias) { - qual = NONANTIALIASED_QUALITY; - } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && data()->clearTypeEnabled) { - qual = ANTIALIASED_QUALITY; - } - - lf.lfQuality = qual; - - lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; - - int hint = FF_DONTCARE; - switch (request.styleHint) { - case QFont::Helvetica: - hint = FF_SWISS; - break; - case QFont::Times: - hint = FF_ROMAN; - break; - case QFont::Courier: - hint = FF_MODERN; - break; - case QFont::OldEnglish: - hint = FF_DECORATIVE; - break; - case QFont::System: - hint = FF_MODERN; - break; - default: - break; - } - - lf.lfPitchAndFamily = DEFAULT_PITCH | hint; - - QString fam = faceName; - if (fam.isEmpty()) - fam = request.families.size() > 0 ? request.families.at(0) : request.family; - if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) { - qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam)); - 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; -} - -QFont QWindowsFontDatabaseBase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In) -{ - if (verticalDPI_In <= 0) - verticalDPI_In = defaultVerticalDPI(); - QFont qFont(QString::fromWCharArray(logFont.lfFaceName)); - qFont.setItalic(logFont.lfItalic); - if (logFont.lfWeight != FW_DONTCARE) - qFont.setWeight(QPlatformFontDatabase::weightFromInteger(logFont.lfWeight)); - const qreal logFontHeight = qAbs(logFont.lfHeight); - qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In)); - qFont.setUnderline(logFont.lfUnderline); - qFont.setOverline(false); - qFont.setStrikeOut(logFont.lfStrikeOut); - return qFont; -} - -// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont() -HFONT QWindowsFontDatabaseBase::systemFont() -{ - static const auto stock_sysfont = - reinterpret_cast(GetStockObject(DEFAULT_GUI_FONT)); - return stock_sysfont; -} - -QFont QWindowsFontDatabaseBase::systemDefaultFont() -{ -#if QT_VERSION >= 0x060000 - // 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); - const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont); -#else - LOGFONT lf; - GetObject(systemFont(), sizeof(lf), &lf); - QFont systemFont = LOGFONT_to_QFont(lf); - // "MS Shell Dlg 2" is the correct system font >= Win2k - if (systemFont.family() == QLatin1String("MS Shell Dlg")) - systemFont.setFamily(QStringLiteral("MS Shell Dlg 2")); - // Qt 5 by (Qt 4) legacy uses GetStockObject(DEFAULT_GUI_FONT) to - // obtain the default GUI font (typically "MS Shell Dlg 2, 8pt"). This has been - // long deprecated; the message font of the NONCLIENTMETRICS structure obtained by - // SystemParametersInfo(SPI_GETNONCLIENTMETRICS) should be used instead (see - // QWindowsTheme::refreshFonts(), typically "Segoe UI, 9pt"), which is larger. -#endif // Qt 5 - qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; - return systemFont; -} - -#if !defined(QT_NO_DIRECTWRITE) -IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const -{ - QSharedPointer fontEngineData = data(); - if (fontEngineData->directWriteFactory == nullptr) { - qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()"; - return nullptr; - } - - CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory); - fontFileLoader.addKey(this, fontData); - - IDWriteFontFile *fontFile = nullptr; - const void *key = this; - - HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key, - sizeof(void *), - fontFileLoader.loader(), - &fontFile); - if (FAILED(hres)) { - qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__); - return nullptr; - } - - BOOL isSupportedFontType; - DWRITE_FONT_FILE_TYPE fontFileType; - DWRITE_FONT_FACE_TYPE fontFaceType; - UINT32 numberOfFaces; - fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); - if (!isSupportedFontType) { - fontFile->Release(); - return nullptr; - } - - // ### 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; - } - - fontFile->Release(); - return directWriteFontFace; -} -#endif // !defined(QT_NO_DIRECTWRITE) - -QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) -{ - QFontEngine *fontEngine = nullptr; - -#if !defined(QT_NO_DIRECTWRITE) - QSharedPointer fontEngineData = data(); - if (fontEngineData->directWriteFactory == nullptr) - return nullptr; - - IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData); - fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace, - pixelSize, - fontEngineData); - - // Get font family from font data - EmbeddedFont font(fontData); - font.updateFromOS2Table(fontEngine); - fontEngine->fontDef.family = font.familyName(); - fontEngine->fontDef.hintingPreference = hintingPreference; - - directWriteFontFace->Release(); -#else // !defined(QT_NO_DIRECTWRITE) - Q_UNUSED(fontData); - Q_UNUSED(pixelSize); - Q_UNUSED(hintingPreference); -#endif - - return fontEngine; -} - -QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint) -{ - switch (styleHint) { - case QFont::Times: - return QStringLiteral("Times New Roman"); - case QFont::Courier: - return QStringLiteral("Courier New"); - case QFont::Monospace: - return QStringLiteral("Courier New"); - case QFont::Cursive: - return QStringLiteral("Comic Sans MS"); - case QFont::Fantasy: - return QStringLiteral("Impact"); - case QFont::Decorative: - return QStringLiteral("Old English"); - case QFont::Helvetica: - return QStringLiteral("Arial"); - case QFont::System: - default: - break; - } - return QStringLiteral("MS Shell Dlg 2"); -} - -// Creation functions - -static const char *other_tryFonts[] = { - "Arial", - "MS UI Gothic", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *jp_tryFonts [] = { - "MS UI Gothic", - "Arial", - "Gulim", - "SimSun", - "PMingLiU", - "Arial Unicode MS", - 0 -}; - -static const char *ch_CN_tryFonts [] = { - "SimSun", - "Arial", - "PMingLiU", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *ch_TW_tryFonts [] = { - "PMingLiU", - "Arial", - "SimSun", - "Gulim", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char *kr_tryFonts[] = { - "Gulim", - "Arial", - "PMingLiU", - "SimSun", - "MS UI Gothic", - "Arial Unicode MS", - 0 -}; - -static const char **tryFonts = nullptr; - -QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &family) -{ - QStringList result; - QFontDatabase db; - if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) { - if (!tryFonts) { - LANGID lid = GetUserDefaultLangID(); - switch (lid&0xff) { - case LANG_CHINESE: // Chinese - if ( lid == 0x0804 || lid == 0x1004) // China mainland and Singapore - tryFonts = ch_CN_tryFonts; - else - tryFonts = ch_TW_tryFonts; // Taiwan, Hong Kong and Macau - break; - case LANG_JAPANESE: - tryFonts = jp_tryFonts; - break; - case LANG_KOREAN: - tryFonts = kr_tryFonts; - break; - default: - tryFonts = other_tryFonts; - break; - } - } - QFontDatabase db; - const QStringList families = db.families(); - const char **tf = tryFonts; - while (tf && *tf) { - // QTBUG-31689, family might be an English alias for a localized font name. - const QString family = QString::fromLatin1(*tf); - if (families.contains(family) || db.hasFamily(family)) - result << family; - ++tf; - } - } - result.append(QStringLiteral("Segoe UI Emoji")); - result.append(QStringLiteral("Segoe UI Symbol")); - return result; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h deleted file mode 100644 index 55763f7c76..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h +++ /dev/null @@ -1,138 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTDATABASEBASE_P_H -#define QWINDOWSFONTDATABASEBASE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include - -#if !defined(QT_NO_DIRECTWRITE) - struct IDWriteFactory; - struct IDWriteGdiInterop; - struct IDWriteFontFace; -#endif - -QT_BEGIN_NAMESPACE - -Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts); - -class QWindowsFontEngineData -{ - Q_DISABLE_COPY_MOVE(QWindowsFontEngineData) -public: - QWindowsFontEngineData(); - ~QWindowsFontEngineData(); - - uint pow_gamma[256]; - - bool clearTypeEnabled = false; - qreal fontSmoothingGamma; - HDC hdc = 0; -#if !defined(QT_NO_DIRECTWRITE) - IDWriteFactory *directWriteFactory = nullptr; - IDWriteGdiInterop *directWriteGdiInterop = nullptr; -#endif -}; - -class QWindowsFontDatabaseBase : public QPlatformFontDatabase -{ -public: - QWindowsFontDatabaseBase(); - ~QWindowsFontDatabaseBase() override; - - QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override; - - static int defaultVerticalDPI(); - static void setDefaultVerticalDPI(int d); - - static QSharedPointer data(); -#if !defined(QT_NO_DIRECTWRITE) - static void createDirectWriteFactory(IDWriteFactory **factory); -#endif - static QFont systemDefaultFont(); - static HFONT systemFont(); - static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName); - static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0); - - static QString familyForStyleHint(QFont::StyleHint styleHint); - static QStringList extraTryFontsForFamily(const QString &family); - - class FontTable{}; - class EmbeddedFont - { - public: - EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) {} - - QString changeFamilyName(const QString &newFamilyName); - QByteArray data() const { return m_fontData; } - void updateFromOS2Table(QFontEngine *fontEngine); - FontTable *tableDirectoryEntry(const QByteArray &tagName); - QString familyName(FontTable *nameTableDirectory = nullptr); - - private: - QByteArray m_fontData; - }; - -protected: - -#if !defined(QT_NO_DIRECTWRITE) - IDWriteFontFace *createDirectWriteFace(const QByteArray &fontData) const; -#endif - -private: - static bool init(QSharedPointer data); -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSFONTDATABASEBASE_P_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp deleted file mode 100644 index 6248041a3d..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp +++ /dev/null @@ -1,1204 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#include "qwindowsfontengine_p.h" -#include "qwindowsnativeimage_p.h" -#include "qwindowsfontdatabase_p.h" -#include -#include "qwindowsfontenginedirectwrite_p.h" - -#include -#include // glyph_metrics_t -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#if !defined(QT_NO_DIRECTWRITE) -# include -# include -#endif - -QT_BEGIN_NAMESPACE - -//### mingw needed define -#ifndef TT_PRIM_CSPLINE -#define TT_PRIM_CSPLINE 3 -#endif - -// GetFontData expects the tags in little endian ;( -#define MAKE_LITTLE_ENDIAN_TAG(ch1, ch2, ch3, ch4) (\ - (((quint32)(ch4)) << 24) | \ - (((quint32)(ch3)) << 16) | \ - (((quint32)(ch2)) << 8) | \ - ((quint32)(ch1)) \ - ) - -// common DC for all fonts - -typedef BOOL (WINAPI *PtrGetCharWidthI)(HDC, UINT, UINT, LPWORD, LPINT); -static PtrGetCharWidthI ptrGetCharWidthI = 0; -static bool resolvedGetCharWidthI = false; - -static void resolveGetCharWidthI() -{ - if (resolvedGetCharWidthI) - return; - resolvedGetCharWidthI = true; - ptrGetCharWidthI = (PtrGetCharWidthI)QSystemLibrary::resolve(QStringLiteral("gdi32"), "GetCharWidthI"); -} - -// general font engine - -QFixed QWindowsFontEngine::lineThickness() const -{ - if(lineWidth > 0) - return lineWidth; - - return QFontEngine::lineThickness(); -} - -static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc) -{ - const auto size = GetOutlineTextMetrics(hdc, 0, nullptr); - auto otm = reinterpret_cast(malloc(size)); - GetOutlineTextMetrics(hdc, size, otm); - return otm; -} - -bool QWindowsFontEngine::hasCFFTable() const -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR; -} - -bool QWindowsFontEngine::hasCMapTable() const -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - return GetFontData(hdc, MAKE_LITTLE_ENDIAN_TAG('c', 'm', 'a', 'p'), 0, 0, 0) != GDI_ERROR; -} - -static inline QString stringFromOutLineTextMetric(const OUTLINETEXTMETRIC *otm, PSTR offset) -{ - const uchar *p = reinterpret_cast(otm) + quintptr(offset); - return QString::fromWCharArray(reinterpret_cast(p)); -} - -void QWindowsFontEngine::getCMap() -{ - ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE) || hasCMapTable(); - - cffTable = hasCFFTable(); - - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - bool symb = false; - if (ttf) { - cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); - cmap = QFontEngine::getCMap(reinterpret_cast(cmapTable.constData()), - cmapTable.size(), &symb, &cmapSize); - } - if (!cmap) { - ttf = false; - symb = false; - } - symbol = symb; - designToDevice = 1; - _faceId.index = 0; - if(cmap) { - OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); - unitsPerEm = int(otm->otmEMSquare); - const QFixed unitsPerEmF(unitsPerEm); - designToDevice = unitsPerEmF / QFixed::fromReal(fontDef.pixelSize); - x_height = int(otm->otmsXHeight); - loadKerningPairs(designToDevice); - _faceId.filename = QFile::encodeName(stringFromOutLineTextMetric(otm, otm->otmpFullName)); - lineWidth = otm->otmsUnderscoreSize; - fsType = otm->otmfsType; - free(otm); - - } else { - unitsPerEm = tm.tmHeight; - } -} - -int QWindowsFontEngine::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout *glyphs) const -{ - int glyph_pos = 0; - { - if (symbol) { - QStringIterator it(str, str + numChars); - while (it.hasNext()) { - const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); - if(!glyphs->glyphs[glyph_pos] && uc < 0x100) - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc + 0xf000); - ++glyph_pos; - } - } else if (ttf) { - QStringIterator it(str, str + numChars); - while (it.hasNext()) { - const uint uc = it.next(); - glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, cmapSize, uc); - ++glyph_pos; - } - } else { - QStringIterator it(str, str + numChars); - while (it.hasNext()) { - const uint uc = it.next(); - if (uc >= tm.tmFirstChar && uc <= tm.tmLastChar) - glyphs->glyphs[glyph_pos] = uc; - else - glyphs->glyphs[glyph_pos] = 0; - ++glyph_pos; - } - } - } - glyphs->numGlyphs = glyph_pos; - return glyph_pos; -} - -/*! - \class QWindowsFontEngine - \brief Standard Windows font engine. - \internal - - Will probably be superseded by a common Free Type font engine in Qt 5.X. -*/ - -QWindowsFontEngine::QWindowsFontEngine(const QString &name, - LOGFONT lf, - const QSharedPointer &fontEngineData) - : QFontEngine(Win), - m_fontEngineData(fontEngineData), - _name(name), - m_logfont(lf), - ttf(0), - hasOutline(0) -{ - qCDebug(lcQpaFonts) << __FUNCTION__ << name << lf.lfHeight; - hfont = CreateFontIndirect(&m_logfont); - if (!hfont) { - qErrnoWarning("%s: CreateFontIndirect failed for family '%s'", __FUNCTION__, qPrintable(name)); - hfont = QWindowsFontDatabase::systemFont(); - } - - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - const BOOL res = GetTextMetrics(hdc, &tm); - if (!res) { - qErrnoWarning("%s: GetTextMetrics failed", __FUNCTION__); - ZeroMemory(&tm, sizeof(TEXTMETRIC)); - } - - fontDef.pixelSize = -lf.lfHeight; - fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); - - cache_cost = tm.tmHeight * tm.tmAveCharWidth * 2000; - getCMap(); - - if (!resolvedGetCharWidthI) - resolveGetCharWidthI(); - - // ### Properties accessed by QWin32PrintEngine (QtPrintSupport) - QVariantMap userData; - userData.insert(QStringLiteral("logFont"), QVariant::fromValue(m_logfont)); - userData.insert(QStringLiteral("hFont"), QVariant::fromValue(hfont)); - userData.insert(QStringLiteral("trueType"), QVariant(bool(ttf))); - setUserData(userData); - - hasUnreliableOutline = (tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) == 0; -} - -QWindowsFontEngine::~QWindowsFontEngine() -{ - if (designAdvances) - free(designAdvances); - - if (widthCache) - free(widthCache); - - // make sure we aren't by accident still selected - SelectObject(m_fontEngineData->hdc, QWindowsFontDatabase::systemFont()); - - if (!DeleteObject(hfont)) - qErrnoWarning("%s: QFontEngineWin: failed to delete font...", __FUNCTION__); - qCDebug(lcQpaFonts) << __FUNCTION__ << _name; - - if (!uniqueFamilyName.isEmpty()) { - if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) { - QPlatformFontDatabase *pfdb = pi->fontDatabase(); - static_cast(pfdb)->derefUniqueFont(uniqueFamilyName); - } - } -} - -glyph_t QWindowsFontEngine::glyphIndex(uint ucs4) const -{ - glyph_t glyph = 0; - - if (symbol) { - glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); - if (glyph == 0 && ucs4 < 0x100) - glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4 + 0xf000); - } else if (ttf) { - glyph = getTrueTypeGlyphIndex(cmap, cmapSize, ucs4); - } else if (ucs4 >= tm.tmFirstChar && ucs4 <= tm.tmLastChar) { - glyph = ucs4; - } - - return glyph; -} - -HGDIOBJ QWindowsFontEngine::selectDesignFont() const -{ - LOGFONT f = m_logfont; - f.lfHeight = -unitsPerEm; - f.lfWidth = 0; - HFONT designFont = CreateFontIndirect(&f); - return SelectObject(m_fontEngineData->hdc, designFont); -} - -bool QWindowsFontEngine::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; - } - - glyphs->numGlyphs = *nglyphs; - *nglyphs = getGlyphIndexes(str, len, glyphs); - - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, flags); - - return true; -} - -inline void calculateTTFGlyphWidth(HDC hdc, UINT glyph, int &width) -{ - if (ptrGetCharWidthI) - ptrGetCharWidthI(hdc, glyph, 1, 0, &width); -} - -void QWindowsFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const -{ - HGDIOBJ oldFont = 0; - HDC hdc = m_fontEngineData->hdc; - if (ttf && (flags & DesignMetrics)) { - for(int i = 0; i < glyphs->numGlyphs; i++) { - unsigned int glyph = glyphs->glyphs[i]; - if(int(glyph) >= designAdvancesSize) { - const int newSize = int(glyph + 256) >> 8 << 8; - designAdvances = reinterpret_cast(realloc(designAdvances, size_t(newSize) * sizeof(QFixed))); - Q_CHECK_PTR(designAdvances); - for(int i = designAdvancesSize; i < newSize; ++i) - designAdvances[i] = -1000000; - designAdvancesSize = newSize; - } - if (designAdvances[glyph] < -999999) { - if (!oldFont) - oldFont = selectDesignFont(); - - int width = 0; - calculateTTFGlyphWidth(hdc, glyph, width); - designAdvances[glyph] = QFixed(width) / designToDevice; - } - glyphs->advances[i] = designAdvances[glyph]; - } - if(oldFont) - DeleteObject(SelectObject(hdc, oldFont)); - } else { - for(int i = 0; i < glyphs->numGlyphs; i++) { - unsigned int glyph = glyphs->glyphs[i]; - - if (glyph >= widthCacheSize) { - const uint newSize = (glyph + 256) >> 8 << 8; - widthCache = reinterpret_cast(realloc(widthCache, newSize * sizeof(QFixed))); - Q_CHECK_PTR(widthCache); - memset(widthCache + widthCacheSize, 0, newSize - widthCacheSize); - widthCacheSize = newSize; - } - glyphs->advances[i] = widthCache[glyph]; - // font-width cache failed - if (glyphs->advances[i].value() == 0) { - int width = 0; - if (!oldFont) - oldFont = SelectObject(hdc, hfont); - - if (!ttf) { - QChar ch[2] = { ushort(glyph), 0 }; - int chrLen = 1; - if (QChar::requiresSurrogates(glyph)) { - ch[0] = QChar::highSurrogate(glyph); - ch[1] = QChar::lowSurrogate(glyph); - ++chrLen; - } - SIZE size = {0, 0}; - GetTextExtentPoint32(hdc, reinterpret_cast(ch), chrLen, &size); - width = size.cx; - } else { - calculateTTFGlyphWidth(hdc, glyph, width); - } - glyphs->advances[i] = width; - // if glyph's within cache range, store it for later - if (width > 0 && width < 0x100) - widthCache[glyph] = uchar(width); - } - } - - if (oldFont) - SelectObject(hdc, oldFont); - } -} - -glyph_metrics_t QWindowsFontEngine::boundingBox(const QGlyphLayout &glyphs) -{ - if (glyphs.numGlyphs == 0) - return glyph_metrics_t(); - - QFixed w = 0; - for (int i = 0; i < glyphs.numGlyphs; ++i) - w += glyphs.effectiveAdvance(i); - - return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0); -} - -bool QWindowsFontEngine::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const -{ - Q_ASSERT(metrics != 0); - - HDC hdc = m_fontEngineData->hdc; - - GLYPHMETRICS gm; - DWORD res = 0; - MAT2 mat; - mat.eM11.value = mat.eM22.value = 1; - mat.eM11.fract = mat.eM22.fract = 0; - mat.eM21.value = mat.eM12.value = 0; - mat.eM21.fract = mat.eM12.fract = 0; - - if (t.type() > QTransform::TxTranslate) { - // We need to set the transform using the HDC's world - // matrix rather than using the MAT2 above, because the - // results provided when transforming via MAT2 does not - // match the glyphs that are drawn using a WorldTransform - XFORM xform; - xform.eM11 = FLOAT(t.m11()); - xform.eM12 = FLOAT(t.m12()); - xform.eM21 = FLOAT(t.m21()); - xform.eM22 = FLOAT(t.m22()); - xform.eDx = 0; - xform.eDy = 0; - SetGraphicsMode(hdc, GM_ADVANCED); - SetWorldTransform(hdc, &xform); - } - - uint format = GGO_METRICS; - if (ttf) - format |= GGO_GLYPH_INDEX; - res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat); - - if (t.type() > QTransform::TxTranslate) { - XFORM xform; - xform.eM11 = xform.eM22 = 1; - xform.eM12 = xform.eM21 = xform.eDx = xform.eDy = 0; - SetWorldTransform(hdc, &xform); - SetGraphicsMode(hdc, GM_COMPATIBLE); - } - - if (res != GDI_ERROR) { - *metrics = glyph_metrics_t(gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y, - int(gm.gmBlackBoxX), int(gm.gmBlackBoxY), - gm.gmCellIncX, gm.gmCellIncY); - return true; - } else { - return false; - } -} - -glyph_metrics_t QWindowsFontEngine::boundingBox(glyph_t glyph, const QTransform &t) -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - - glyph_metrics_t glyphMetrics; - bool success = getOutlineMetrics(glyph, t, &glyphMetrics); - - if (!ttf && !success) { - // Bitmap fonts - wchar_t ch = wchar_t(glyph); - ABCFLOAT abc; - GetCharABCWidthsFloat(hdc, ch, ch, &abc); - int width = qRound(abc.abcfB); - - return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t); - } - - return glyphMetrics; -} - -namespace { -# pragma pack(1) - - struct OS2Table - { - quint16 version; - qint16 avgCharWidth; - quint16 weightClass; - quint16 widthClass; - quint16 type; - qint16 subscriptXSize; - qint16 subscriptYSize; - qint16 subscriptXOffset; - qint16 subscriptYOffset; - qint16 superscriptXSize; - qint16 superscriptYSize; - qint16 superscriptXOffset; - qint16 superscriptYOffset; - qint16 strikeOutSize; - qint16 strikeOutPosition; - qint16 familyClass; - quint8 panose[10]; - quint32 unicodeRanges[4]; - quint8 vendorID[4]; - quint16 selection; - quint16 firstCharIndex; - quint16 lastCharIndex; - qint16 typoAscender; - qint16 typoDescender; - qint16 typoLineGap; - quint16 winAscent; - quint16 winDescent; - quint32 codepageRanges[2]; - qint16 height; - qint16 capHeight; - quint16 defaultChar; - quint16 breakChar; - quint16 maxContext; - }; - -# pragma pack() -} - -QFixed QWindowsFontEngine::capHeight() const -{ - const QByteArray tableData = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - if (size_t(tableData.size()) >= sizeof(OS2Table)) { - const OS2Table *table = reinterpret_cast(tableData.constData()); - if (qFromBigEndian(table->version) >= 2) { - qint16 capHeight = qFromBigEndian(table->capHeight); - if (capHeight > 0) - return QFixed(capHeight) / designToDevice; - } - } - return calculatedCapHeight(); -} - -QFixed QWindowsFontEngine::xHeight() const -{ - if(x_height >= 0) - return x_height; - return QFontEngine::xHeight(); -} - -QFixed QWindowsFontEngine::averageCharWidth() const -{ - return tm.tmAveCharWidth; -} - -qreal QWindowsFontEngine::maxCharWidth() const -{ - return tm.tmMaxCharWidth; -} - -enum { max_font_count = 256 }; -static const ushort char_table[] = { - 40, - 67, - 70, - 75, - 86, - 88, - 89, - 91, - 102, - 114, - 124, - 127, - 205, - 645, - 884, - 922, - 1070, - 12386, - 0 -}; - -static const int char_table_entries = sizeof(char_table)/sizeof(ushort); - -#ifndef Q_CC_MINGW -void QWindowsFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing) -{ - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - - if (ttf) { - ABC abcWidths; - GetCharABCWidthsI(hdc, glyph, 1, 0, &abcWidths); - if (leftBearing) - *leftBearing = abcWidths.abcA; - if (rightBearing) - *rightBearing = abcWidths.abcC; - } else { - QFontEngine::getGlyphBearings(glyph, leftBearing, rightBearing); - } -} -#endif // Q_CC_MINGW - -void QWindowsFontEngine::initializeHeightMetrics() const -{ - m_ascent = tm.tmAscent; - m_descent = tm.tmDescent; - m_leading = tm.tmExternalLeading; - - QFontEngine::initializeHeightMetrics(); -} - -bool QWindowsFontEngine::hasUnreliableGlyphOutline() const -{ - return hasUnreliableOutline || QFontEngine::hasUnreliableGlyphOutline(); -} - -qreal QWindowsFontEngine::minLeftBearing() const -{ - if (lbearing == SHRT_MIN) - minRightBearing(); // calculates both - - return lbearing; -} - -qreal QWindowsFontEngine::minRightBearing() const -{ - if (rbearing == SHRT_MIN) { - int ml = 0; - int mr = 0; - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - if (ttf) { - ABC *abc = 0; - int n = tm.tmLastChar - tm.tmFirstChar; - if (n <= max_font_count) { - abc = new ABC[n+1]; - GetCharABCWidths(hdc, tm.tmFirstChar, tm.tmLastChar, abc); - } else { - abc = new ABC[char_table_entries+1]; - for(int i = 0; i < char_table_entries; i++) - GetCharABCWidths(hdc, char_table[i], char_table[i], abc + i); - n = char_table_entries; - } - ml = abc[0].abcA; - mr = abc[0].abcC; - for (int i = 1; i < n; i++) { - if (abc[i].abcA + abc[i].abcB + abc[i].abcC != 0) { - ml = qMin(ml,abc[i].abcA); - mr = qMin(mr,abc[i].abcC); - } - } - delete [] abc; - } else { - ABCFLOAT *abc = 0; - int n = tm.tmLastChar - tm.tmFirstChar+1; - if (n <= max_font_count) { - abc = new ABCFLOAT[n]; - GetCharABCWidthsFloat(hdc, tm.tmFirstChar, tm.tmLastChar, abc); - } else { - abc = new ABCFLOAT[char_table_entries]; - for(int i = 0; i < char_table_entries; i++) - GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i); - n = char_table_entries; - } - float fml = abc[0].abcfA; - float fmr = abc[0].abcfC; - for (int i=1; i(dataBuffer + headerOffset); - - QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch)); - path->moveTo(lastPoint + oset); - offset += sizeof(TTPOLYGONHEADER); - while (offset < headerOffset + ttph->cb) { - const TTPOLYCURVE *curve = reinterpret_cast(dataBuffer + offset); - switch (curve->wType) { - case TT_PRIM_LINE: { - for (int i=0; icpfx; ++i) { - QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; - path->lineTo(p); - } - break; - } - case TT_PRIM_QSPLINE: { - const QPainterPath::Element &elm = path->elementAt(path->elementCount()-1); - QPointF prev(elm.x, elm.y); - QPointF endPoint; - for (int i=0; icpfx - 1; ++i) { - QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset; - QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset; - if (i < curve->cpfx - 2) { - endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2); - } else { - endPoint = p2; - } - - path->quadTo(p1, endPoint); - prev = endPoint; - } - - break; - } - case TT_PRIM_CSPLINE: { - for (int i=0; icpfx; ) { - QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; - QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; - QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset; - path->cubicTo(p2, p3, p4); - } - break; - } - default: - qWarning("QFontEngineWin::addOutlineToPath, unhandled switch case"); - } - offset += sizeof(TTPOLYCURVE) + (curve->cpfx-1) * sizeof(POINTFX); - } - path->closeSubpath(); - headerOffset += ttph->cb; - } - delete [] dataBuffer; - - return true; -} - -void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags) -{ - LOGFONT lf = m_logfont; - // The sign must be negative here to make sure we match against character height instead of - // hinted cell height. This ensures that we get linear matching, and we need this for - // paths since we later on apply a scaling transform to the glyph outline to get the - // font at the correct pixel size. - lf.lfHeight = -unitsPerEm; - lf.lfWidth = 0; - HFONT hf = CreateFontIndirect(&lf); - HDC hdc = m_fontEngineData->hdc; - HGDIOBJ oldfont = SelectObject(hdc, hf); - - qreal scale = qreal(fontDef.pixelSize) / unitsPerEm; - qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0; - for(int i = 0; i < nglyphs; ++i) { - if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0, - scale, stretch)) { - // Some windows fonts, like "Modern", are vector stroke - // fonts, which are reported as TMPF_VECTOR but do not - // support GetGlyphOutline, and thus we set this bit so - // that addOutLineToPath can check it and return safely... - hasOutline = false; - break; - } - } - DeleteObject(SelectObject(hdc, oldfont)); -} - -void QWindowsFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, - QPainterPath *path, QTextItem::RenderFlags flags) -{ - if(tm.tmPitchAndFamily & (TMPF_TRUETYPE | TMPF_VECTOR)) { - hasOutline = true; - QFontEngine::addOutlineToPath(x, y, glyphs, path, flags); - if (hasOutline) { - // has_outline is set to false if addGlyphToPath gets - // false from GetGlyphOutline, meaning its not an outline - // font. - return; - } - } - QFontEngine::addBitmapFontToPath(x, y, glyphs, path, flags); -} - -QFontEngine::FaceId QWindowsFontEngine::faceId() const -{ - return _faceId; -} - -QT_BEGIN_INCLUDE_NAMESPACE -#include -QT_END_INCLUDE_NAMESPACE - -int QWindowsFontEngine::synthesized() const -{ - if(synthesized_flags == -1) { - synthesized_flags = 0; - if(ttf) { - const DWORD HEAD = MAKE_LITTLE_ENDIAN_TAG('h', 'e', 'a', 'd'); - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - uchar data[4]; - GetFontData(hdc, HEAD, 44, &data, 4); - USHORT macStyle = qt_getUShort(data); - if (tm.tmItalic && !(macStyle & 2)) - synthesized_flags = SynthesizedItalic; - if (fontDef.stretch != 100 && ttf) - synthesized_flags |= SynthesizedStretch; - if (tm.tmWeight >= 500 && tm.tmWeight < 750 && !(macStyle & 1)) - synthesized_flags |= SynthesizedBold; - //qDebug() << "font is" << _name << - // "it=" << (macStyle & 2) << fontDef.style << "flags=" << synthesized_flags; - } - } - return synthesized_flags; -} - -QFixed QWindowsFontEngine::emSquareSize() const -{ - return unitsPerEm; -} - -QFontEngine::Properties QWindowsFontEngine::properties() const -{ - LOGFONT lf = m_logfont; - lf.lfHeight = unitsPerEm; - HFONT hf = CreateFontIndirect(&lf); - HDC hdc = m_fontEngineData->hdc; - HGDIOBJ oldfont = SelectObject(hdc, hf); - OUTLINETEXTMETRIC *otm = getOutlineTextMetric(hdc); - Properties p; - p.emSquare = unitsPerEm; - p.italicAngle = otm->otmItalicAngle; - const QByteArray name = stringFromOutLineTextMetric(otm, otm->otmpFamilyName).toLatin1() - + stringFromOutLineTextMetric(otm, otm->otmpStyleName).toLatin1(); - p.postscriptName = QFontEngine::convertToPostscriptFontFamilyName(name); - p.boundingBox = QRectF(otm->otmrcFontBox.left, -otm->otmrcFontBox.top, - otm->otmrcFontBox.right - otm->otmrcFontBox.left, - otm->otmrcFontBox.top - otm->otmrcFontBox.bottom); - p.ascent = otm->otmAscent; - p.descent = -otm->otmDescent; - p.leading = int(otm->otmLineGap); - p.capHeight = 0; - p.lineWidth = otm->otmsUnderscoreSize; - free(otm); - DeleteObject(SelectObject(hdc, oldfont)); - return p; -} - -void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) -{ - LOGFONT lf = m_logfont; - lf.lfHeight = -unitsPerEm; - int flags = synthesized(); - if(flags & SynthesizedItalic) - lf.lfItalic = false; - lf.lfWidth = 0; - HFONT hf = CreateFontIndirect(&lf); - HDC hdc = m_fontEngineData->hdc; - HGDIOBJ oldfont = SelectObject(hdc, hf); - QFixedPoint p; - p.x = 0; - p.y = 0; - addGlyphToPath(glyph, p, hdc, path, ttf, metrics); - DeleteObject(SelectObject(hdc, oldfont)); -} - -bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const -{ - if (!ttf && !cffTable) - return false; - HDC hdc = m_fontEngineData->hdc; - SelectObject(hdc, hfont); - DWORD t = qbswap(tag); - *length = GetFontData(hdc, t, 0, buffer, *length); - Q_ASSERT(*length == GDI_ERROR || int(*length) > 0); - return *length != GDI_ERROR; -} - -#if !defined(CLEARTYPE_QUALITY) -# define CLEARTYPE_QUALITY 5 -#endif - -QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph, int margin, - const QTransform &t, - QImage::Format mask_format) -{ - Q_UNUSED(mask_format) - glyph_metrics_t gm = boundingBox(glyph); - -// printf(" -> for glyph %4x\n", glyph); - - int gx = gm.x.toInt(); - int gy = gm.y.toInt(); - int iw = gm.width.toInt(); - int ih = gm.height.toInt(); - - if (iw <= 0 || ih <= 0) - return 0; - - bool has_transformation = t.type() > QTransform::TxTranslate; - - unsigned int options = ttf ? ETO_GLYPH_INDEX : 0; - XFORM xform; - - if (has_transformation) { - xform.eM11 = FLOAT(t.m11()); - xform.eM12 = FLOAT(t.m12()); - xform.eM21 = FLOAT(t.m21()); - xform.eM22 = FLOAT(t.m22()); - xform.eDx = margin; - xform.eDy = margin; - - const HDC hdc = m_fontEngineData->hdc; - - SetGraphicsMode(hdc, GM_ADVANCED); - SetWorldTransform(hdc, &xform); - HGDIOBJ old_font = SelectObject(hdc, font); - - const UINT ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0); - GLYPHMETRICS tgm; - MAT2 mat; - memset(&mat, 0, sizeof(mat)); - mat.eM11.value = mat.eM22.value = 1; - - const DWORD result = GetGlyphOutline(hdc, glyph, ggo_options, &tgm, 0, 0, &mat); - - XFORM identity = {1, 0, 0, 1, 0, 0}; - SetWorldTransform(hdc, &identity); - SetGraphicsMode(hdc, GM_COMPATIBLE); - SelectObject(hdc, old_font); - - if (result == GDI_ERROR) { - const int errorCode = int(GetLastError()); - qErrnoWarning(errorCode, "QWinFontEngine: unable to query transformed glyph metrics (GetGlyphOutline() failed, error %d)...", errorCode); - return 0; - } - - iw = int(tgm.gmBlackBoxX); - ih = int(tgm.gmBlackBoxY); - - xform.eDx -= tgm.gmptGlyphOrigin.x; - xform.eDy += tgm.gmptGlyphOrigin.y; - } - - // The padding here needs to be kept in sync with the values in alphaMapBoundingBox. - QWindowsNativeImage *ni = new QWindowsNativeImage(iw + 2 * margin, - ih + 2 * margin, - QWindowsNativeImage::systemFormat()); - - /*If cleartype is enabled we use the standard system format even on Windows CE - and not the special textbuffer format we have to use if cleartype is disabled*/ - - ni->image().fill(0xffffffff); - - HDC hdc = ni->hdc(); - - SelectObject(hdc, GetStockObject(NULL_BRUSH)); - SelectObject(hdc, GetStockObject(BLACK_PEN)); - SetTextColor(hdc, RGB(0,0,0)); - SetBkMode(hdc, TRANSPARENT); - SetTextAlign(hdc, TA_BASELINE); - - HGDIOBJ old_font = SelectObject(hdc, font); - - if (has_transformation) { - SetGraphicsMode(hdc, GM_ADVANCED); - SetWorldTransform(hdc, &xform); - ExtTextOut(hdc, 0, 0, options, 0, reinterpret_cast(&glyph), 1, 0); - } else { - ExtTextOut(hdc, -gx + margin, -gy + margin, options, 0, reinterpret_cast(&glyph), 1, 0); - } - - SelectObject(hdc, old_font); - return ni; -} - -glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat format) -{ - int margin = 0; - if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB) - margin = glyphMargin(QFontEngine::Format_A32); - glyph_metrics_t gm = boundingBox(glyph, matrix); - gm.width += margin * 2; - gm.height += margin * 2; - return gm; -} - -QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xform) -{ - HFONT font = hfont; - - bool clearTypeTemporarilyDisabled = (m_fontEngineData->clearTypeEnabled && m_logfont.lfQuality != NONANTIALIASED_QUALITY); - if (clearTypeTemporarilyDisabled) { - LOGFONT lf = m_logfont; - lf.lfQuality = ANTIALIASED_QUALITY; - font = CreateFontIndirect(&lf); - } - QImage::Format mask_format = QWindowsNativeImage::systemFormat(); - mask_format = QImage::Format_RGB32; - - const QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, 0, xform, mask_format); - if (mask == 0) { - if (m_fontEngineData->clearTypeEnabled) - DeleteObject(font); - return QImage(); - } - - QImage alphaMap(mask->width(), mask->height(), QImage::Format_Alpha8); - - - // Copy data... Cannot use QPainter here as GDI has messed up the - // Alpha channel of the ni.image pixels... - for (int y=0; yheight(); ++y) { - uchar *dest = alphaMap.scanLine(y); - if (mask->image().format() == QImage::Format_RGB16) { - const qint16 *src = reinterpret_cast(mask->image().constScanLine(y)); - for (int x=0; xwidth(); ++x) - dest[x] = 255 - qGray(src[x]); - } else { - const uint *src = reinterpret_cast(mask->image().constScanLine(y)); - for (int x=0; xwidth(); ++x) { - if (QWindowsNativeImage::systemFormat() == QImage::Format_RGB16) - dest[x] = 255 - qGray(src[x]); - else - dest[x] = 255 - (m_fontEngineData->pow_gamma[qGray(src[x])] * 255. / 2047.); - } - } - } - - // Cleanup... - delete mask; - if (clearTypeTemporarilyDisabled) { - DeleteObject(font); - } - - return alphaMap; -} - -#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C -#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D - -QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTransform &t) -{ - HFONT font = hfont; - - UINT contrast; - SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0); - SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast(quintptr(1000)), 0); - - int margin = glyphMargin(QFontEngine::Format_A32); - QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32); - SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, reinterpret_cast(quintptr(contrast)), 0); - - if (mask == 0) - return QImage(); - - // Gracefully handle the odd case when the display is 16-bit - const QImage source = mask->image().depth() == 32 - ? mask->image() - : mask->image().convertToFormat(QImage::Format_RGB32); - - QImage rgbMask(mask->width(), mask->height(), QImage::Format_RGB32); - for (int y=0; yheight(); ++y) { - auto dest = reinterpret_cast(rgbMask.scanLine(y)); - const uint *src = reinterpret_cast(source.constScanLine(y)); - for (int x=0; xwidth(); ++x) { - dest[x] = 0xffffffff - (0x00ffffff & src[x]); - } - } - - delete mask; - - return rgbMask; -} - -QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const -{ - QFontDef request = fontDef; - QString actualFontName = request.family; - if (!uniqueFamilyName.isEmpty()) - request.family = uniqueFamilyName; - request.pixelSize = pixelSize; - const QString faceName = QString::fromWCharArray(m_logfont.lfFaceName); - - QFontEngine *fontEngine = - QWindowsFontDatabase::createEngine(request, faceName, - QWindowsFontDatabase::defaultVerticalDPI(), - m_fontEngineData); - if (fontEngine) { - fontEngine->fontDef.family = actualFontName; - if (!uniqueFamilyName.isEmpty()) { - static_cast(fontEngine)->setUniqueFamilyName(uniqueFamilyName); - if (QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration()) { - QPlatformFontDatabase *pfdb = pi->fontDatabase(); - static_cast(pfdb)->refUniqueFont(uniqueFamilyName); - } - } - } - return fontEngine; -} - -Qt::HANDLE QWindowsFontEngine::handle() const -{ - return hfont; -} - -void QWindowsFontEngine::initFontInfo(const QFontDef &request, - int dpi) -{ - fontDef = request; // most settings are equal - HDC dc = m_fontEngineData->hdc; - SelectObject(dc, hfont); - wchar_t n[64]; - GetTextFace(dc, 64, n); - fontDef.family = QString::fromWCharArray(n); - fontDef.fixedPitch = !(tm.tmPitchAndFamily & TMPF_FIXED_PITCH); - if (fontDef.pointSize < 0) { - fontDef.pointSize = fontDef.pixelSize * 72. / dpi; - } else if (fontDef.pixelSize == -1) { - fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); - } -} - -bool QWindowsFontEngine::supportsTransformation(const QTransform &transform) const -{ - // Support all transformations for ttf files, and translations for raster fonts - return ttf || transform.type() <= QTransform::TxTranslate; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h deleted file mode 100644 index 8a676affcd..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h +++ /dev/null @@ -1,175 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTENGINE_H -#define QWINDOWSFONTENGINE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include -#include - -#include - -QT_BEGIN_NAMESPACE - -class QWindowsNativeImage; -class QWindowsFontEngineData; - -class QWindowsFontEngine : public QFontEngine -{ - Q_DISABLE_COPY_MOVE(QWindowsFontEngine) -public: - QWindowsFontEngine(const QString &name, LOGFONT lf, - const QSharedPointer &fontEngineData); - - ~QWindowsFontEngine() override; - void initFontInfo(const QFontDef &request, - int dpi); - - QFixed lineThickness() const override; - Properties properties() const override; - void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override; - FaceId faceId() const override; - bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; - int synthesized() const override; - 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; - void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; - - void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override; - void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags) override; - - HGDIOBJ selectDesignFont() const; - - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; - glyph_metrics_t boundingBox(glyph_t g) override { return boundingBox(g, QTransform()); } - glyph_metrics_t boundingBox(glyph_t g, const QTransform &t) override; - - - QFixed xHeight() const override; - QFixed capHeight() const override; - QFixed averageCharWidth() const override; - qreal maxCharWidth() const override; - qreal minLeftBearing() const override; - qreal minRightBearing() const override; - - QImage alphaMapForGlyph(glyph_t t) override { return alphaMapForGlyph(t, QTransform()); } - QImage alphaMapForGlyph(glyph_t, const QTransform &xform) override; - QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override; - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) override; - - QFontEngine *cloneWithSize(qreal pixelSize) const override; - Qt::HANDLE handle() const override; - bool supportsTransformation(const QTransform &transform) const override; - -#ifndef Q_CC_MINGW - void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0) override; -#endif - - bool hasUnreliableGlyphOutline() const override; - - int getGlyphIndexes(const QChar *ch, int numChars, QGlyphLayout *glyphs) const; - void getCMap(); - - bool getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph_metrics_t *metrics) const; - - const QSharedPointer &fontEngineData() const { return m_fontEngineData; } - - void setUniqueFamilyName(const QString &newName) { uniqueFamilyName = newName; } - -protected: - void initializeHeightMetrics() const override; - -private: - QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform, - QImage::Format mask_format); - bool hasCFFTable() const; - bool hasCMapTable() const; - - const QSharedPointer m_fontEngineData; - - const QString _name; - QString uniqueFamilyName; - HFONT hfont = 0; - const LOGFONT m_logfont; - uint ttf : 1; - uint hasOutline : 1; - uint hasUnreliableOutline : 1; - uint cffTable : 1; - TEXTMETRIC tm; - const unsigned char *cmap = nullptr; - int cmapSize = 0; - QByteArray cmapTable; - mutable qreal lbearing = SHRT_MIN; - mutable qreal rbearing = SHRT_MIN; - QFixed designToDevice; - int unitsPerEm = 0; - QFixed x_height = -1; - FaceId _faceId; - - mutable int synthesized_flags = -1; - mutable QFixed lineWidth = -1; - mutable unsigned char *widthCache = nullptr; - mutable uint widthCacheSize = 0; - mutable QFixed *designAdvances = nullptr; - mutable int designAdvancesSize = 0; -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(HFONT) -Q_DECLARE_METATYPE(LOGFONT) - -#endif // QWINDOWSFONTENGINE_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp deleted file mode 100644 index d96e65a532..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp +++ /dev/null @@ -1,1030 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#ifndef QT_NO_DIRECTWRITE - -#include "qwindowsfontenginedirectwrite_p.h" -#include "qwindowsfontdatabase_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(QT_USE_DIRECTWRITE2) -# include -#else -# include -#endif - -#include - -QT_BEGIN_NAMESPACE - -// Clang does not consider __declspec(nothrow) as nothrow -QT_WARNING_DISABLE_CLANG("-Wmicrosoft-exception-spec") - -// Convert from design units to logical pixels -#define DESIGN_TO_LOGICAL(DESIGN_UNIT_VALUE) \ - QFixed::fromReal((qreal(DESIGN_UNIT_VALUE) / qreal(m_unitsPerEm)) * fontDef.pixelSize) - -namespace { - - class GeometrySink: public IDWriteGeometrySink - { - Q_DISABLE_COPY_MOVE(GeometrySink) - public: - GeometrySink(QPainterPath *path) - : m_refCount(0), m_path(path) - { - Q_ASSERT(m_path != 0); - } - virtual ~GeometrySink() = default; - - IFACEMETHOD_(void, AddBeziers)(const D2D1_BEZIER_SEGMENT *beziers, UINT bezierCount); - IFACEMETHOD_(void, AddLines)(const D2D1_POINT_2F *points, UINT pointCount); - IFACEMETHOD_(void, BeginFigure)(D2D1_POINT_2F startPoint, D2D1_FIGURE_BEGIN figureBegin); - IFACEMETHOD(Close)(); - IFACEMETHOD_(void, EndFigure)(D2D1_FIGURE_END figureEnd); - IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode); - IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags); - - IFACEMETHOD_(unsigned long, AddRef)(); - IFACEMETHOD_(unsigned long, Release)(); - IFACEMETHOD(QueryInterface)(IID const &riid, void **ppvObject); - - private: - inline static QPointF fromD2D1_POINT_2F(const D2D1_POINT_2F &inp) - { - return QPointF(inp.x, inp.y); - } - - unsigned long m_refCount; - QPointF m_startPoint; - QPainterPath *m_path; - }; - - void GeometrySink::AddBeziers(const D2D1_BEZIER_SEGMENT *beziers, - UINT bezierCount) - { - for (uint i=0; icubicTo(c1, c2, p2); - } - } - - void GeometrySink::AddLines(const D2D1_POINT_2F *points, UINT pointsCount) - { - for (uint i=0; ilineTo(fromD2D1_POINT_2F(points[i])); - } - - void GeometrySink::BeginFigure(D2D1_POINT_2F startPoint, - D2D1_FIGURE_BEGIN /*figureBegin*/) - { - m_startPoint = fromD2D1_POINT_2F(startPoint); - m_path->moveTo(m_startPoint); - } - - IFACEMETHODIMP GeometrySink::Close() - { - return E_NOTIMPL; - } - - void GeometrySink::EndFigure(D2D1_FIGURE_END figureEnd) - { - if (figureEnd == D2D1_FIGURE_END_CLOSED) - m_path->closeSubpath(); - } - - void GeometrySink::SetFillMode(D2D1_FILL_MODE fillMode) - { - m_path->setFillRule(fillMode == D2D1_FILL_MODE_ALTERNATE - ? Qt::OddEvenFill - : Qt::WindingFill); - } - - void GeometrySink::SetSegmentFlags(D2D1_PATH_SEGMENT /*vertexFlags*/) - { - /* Not implemented */ - } - - IFACEMETHODIMP_(unsigned long) GeometrySink::AddRef() - { - return InterlockedIncrement(&m_refCount); - } - - IFACEMETHODIMP_(unsigned long) GeometrySink::Release() - { - unsigned long newCount = InterlockedDecrement(&m_refCount); - if (newCount == 0) - { - delete this; - return 0; - } - - return newCount; - } - - IFACEMETHODIMP GeometrySink::QueryInterface(IID const &riid, void **ppvObject) - { - if (__uuidof(IDWriteGeometrySink) == riid) { - *ppvObject = this; - } else if (__uuidof(IUnknown) == riid) { - *ppvObject = this; - } else { - *ppvObject = NULL; - return E_FAIL; - } - - AddRef(); - return S_OK; - } - -} - -static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE renderMode) -{ - switch (renderMode) { - case DWRITE_RENDERING_MODE_GDI_CLASSIC: - return DWRITE_MEASURING_MODE_GDI_CLASSIC; - case DWRITE_RENDERING_MODE_GDI_NATURAL: - return DWRITE_MEASURING_MODE_GDI_NATURAL; - default: - return DWRITE_MEASURING_MODE_NATURAL; - } -} - -static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPreference hintingPreference) -{ - if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting) - hintingPreference = QFont::PreferVerticalHinting; - - switch (hintingPreference) { - case QFont::PreferNoHinting: - return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC; - case QFont::PreferVerticalHinting: - return DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL; - default: - return DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; - } -} - -/*! - \class QWindowsFontEngineDirectWrite - \brief Windows font engine using Direct Write. - \internal - - Font engine for subpixel positioned text on Windows Vista - (with platform update) and later. If selected during - configuration, the engine will be selected only when the hinting - preference of a font is set to None or Vertical hinting, or - when fontengine=directwrite is selected as platform option. -*/ - -QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, - qreal pixelSize, - const QSharedPointer &d) - : QFontEngine(DirectWrite) - , m_fontEngineData(d) - , m_directWriteFontFace(directWriteFontFace) - , m_directWriteBitmapRenderTarget(0) - , m_lineThickness(-1) - , m_unitsPerEm(-1) - , m_capHeight(-1) - , m_xHeight(-1) -{ - qCDebug(lcQpaFonts) << __FUNCTION__ << pixelSize; - - Q_ASSERT(m_directWriteFontFace); - - m_fontEngineData->directWriteFactory->AddRef(); - m_directWriteFontFace->AddRef(); - - fontDef.pixelSize = pixelSize; - collectMetrics(); - cache_cost = (m_ascent.toInt() + m_descent.toInt()) * m_xHeight.toInt() * 2000; -} - -QWindowsFontEngineDirectWrite::~QWindowsFontEngineDirectWrite() -{ - qCDebug(lcQpaFonts) << __FUNCTION__; - - m_fontEngineData->directWriteFactory->Release(); - m_directWriteFontFace->Release(); - - if (m_directWriteBitmapRenderTarget != 0) - m_directWriteBitmapRenderTarget->Release(); - - if (!m_uniqueFamilyName.isEmpty()) { - QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); - static_cast(pfdb)->derefUniqueFont(m_uniqueFamilyName); - } -} - -#ifndef Q_CC_MINGW -typedef IDWriteLocalFontFileLoader QIdWriteLocalFontFileLoader; - -static UUID uuidIdWriteLocalFontFileLoader() -{ - return __uuidof(IDWriteLocalFontFileLoader); -} -#else // !Q_CC_MINGW -DECLARE_INTERFACE_(QIdWriteLocalFontFileLoader, IDWriteFontFileLoader) -{ - STDMETHOD(GetFilePathLengthFromKey)(THIS_ void const *, UINT32, UINT32*) PURE; - STDMETHOD(GetFilePathFromKey)(THIS_ void const *, UINT32, WCHAR *, UINT32) PURE; - STDMETHOD(GetLastWriteTimeFromKey)(THIS_ void const *, UINT32, FILETIME *) PURE; -}; - -static UUID uuidIdWriteLocalFontFileLoader() -{ - static const UUID result = { 0xb2d9f3ec, 0xc9fe, 0x4a11, {0xa2, 0xec, 0xd8, 0x62, 0x8, 0xf7, 0xc0, 0xa2}}; - return result; -} -#endif // Q_CC_MINGW - -QString QWindowsFontEngineDirectWrite::filenameFromFontFile(IDWriteFontFile *fontFile) -{ - IDWriteFontFileLoader *loader = nullptr; - - HRESULT hr = fontFile->GetLoader(&loader); - if (FAILED(hr)) { - qErrnoWarning("%s: GetLoader failed", __FUNCTION__); - return QString(); - } - - QIdWriteLocalFontFileLoader *localLoader = nullptr; - hr = loader->QueryInterface(uuidIdWriteLocalFontFileLoader(), - reinterpret_cast(&localLoader)); - - const void *fontFileReferenceKey = nullptr; - UINT32 fontFileReferenceKeySize = 0; - if (SUCCEEDED(hr)) { - hr = fontFile->GetReferenceKey(&fontFileReferenceKey, - &fontFileReferenceKeySize); - if (FAILED(hr)) - qErrnoWarning(hr, "%s: GetReferenceKey failed", __FUNCTION__); - } - - UINT32 filePathLength = 0; - if (SUCCEEDED(hr)) { - hr = localLoader->GetFilePathLengthFromKey(fontFileReferenceKey, - fontFileReferenceKeySize, - &filePathLength); - if (FAILED(hr)) - qErrnoWarning(hr, "GetFilePathLength failed", __FUNCTION__); - } - - QString ret; - if (SUCCEEDED(hr) && filePathLength > 0) { - QVarLengthArray filePath(filePathLength + 1); - - hr = localLoader->GetFilePathFromKey(fontFileReferenceKey, - fontFileReferenceKeySize, - filePath.data(), - filePathLength + 1); - if (FAILED(hr)) - qErrnoWarning(hr, "%s: GetFilePathFromKey failed", __FUNCTION__); - else - ret = QString::fromWCharArray(filePath.data()); - } - - if (localLoader != nullptr) - localLoader->Release(); - - if (loader != nullptr) - loader->Release(); - return ret; -} - -void QWindowsFontEngineDirectWrite::initializeHeightMetrics() const -{ - DWRITE_FONT_METRICS metrics; - m_directWriteFontFace->GetMetrics(&metrics); - - m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); - m_descent = DESIGN_TO_LOGICAL(metrics.descent); - m_leading = DESIGN_TO_LOGICAL(metrics.lineGap); - - QFontEngine::initializeHeightMetrics(); -} - -void QWindowsFontEngineDirectWrite::collectMetrics() -{ - DWRITE_FONT_METRICS metrics; - - m_directWriteFontFace->GetMetrics(&metrics); - m_unitsPerEm = metrics.designUnitsPerEm; - - m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); - m_capHeight = DESIGN_TO_LOGICAL(metrics.capHeight); - m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); - m_underlinePosition = DESIGN_TO_LOGICAL(metrics.underlinePosition); - - IDWriteFontFile *fontFile = nullptr; - UINT32 numberOfFiles = 1; - if (SUCCEEDED(m_directWriteFontFace->GetFiles(&numberOfFiles, &fontFile))) { - m_faceId.filename = QFile::encodeName(filenameFromFontFile(fontFile)); - fontFile->Release(); - } - - QByteArray table = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a')); - const int advanceWidthMaxLocation = 10; - if (table.size() >= advanceWidthMaxLocation + int(sizeof(quint16))) { - quint16 advanceWidthMax = qFromBigEndian(table.constData() + advanceWidthMaxLocation); - m_maxAdvanceWidth = DESIGN_TO_LOGICAL(advanceWidthMax); - } -} - -QFixed QWindowsFontEngineDirectWrite::underlinePosition() const -{ - if (m_underlinePosition > 0) - return m_underlinePosition; - else - return QFontEngine::underlinePosition(); -} - -QFixed QWindowsFontEngineDirectWrite::lineThickness() const -{ - if (m_lineThickness > 0) - return m_lineThickness; - else - return QFontEngine::lineThickness(); -} - -bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, uint *length) const -{ - bool ret = false; - - const void *tableData = 0; - UINT32 tableSize; - void *tableContext = 0; - BOOL exists; - HRESULT hr = m_directWriteFontFace->TryGetFontTable(qbswap(tag), - &tableData, &tableSize, - &tableContext, &exists); - if (SUCCEEDED(hr)) { - if (exists) { - ret = true; - if (buffer && *length >= tableSize) - memcpy(buffer, tableData, tableSize); - *length = tableSize; - Q_ASSERT(int(*length) > 0); - } - m_directWriteFontFace->ReleaseFontTable(tableContext); - } else { - qErrnoWarning("%s: TryGetFontTable failed", __FUNCTION__); - } - - return ret; -} - -QFixed QWindowsFontEngineDirectWrite::emSquareSize() const -{ - if (m_unitsPerEm > 0) - return m_unitsPerEm; - else - return QFontEngine::emSquareSize(); -} - -glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const -{ - UINT16 glyphIndex; - - HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(&ucs4, 1, &glyphIndex); - if (FAILED(hr)) { - qErrnoWarning("%s: glyphIndex failed", __FUNCTION__); - glyphIndex = 0; - } - - return glyphIndex; -} - -bool 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; - } - - QVarLengthArray codePoints(len); - int actualLength = 0; - QStringIterator it(str, str + len); - while (it.hasNext()) - codePoints[actualLength++] = it.next(); - - QVarLengthArray glyphIndices(actualLength); - HRESULT hr = m_directWriteFontFace->GetGlyphIndicesW(codePoints.data(), actualLength, - glyphIndices.data()); - if (FAILED(hr)) { - qErrnoWarning("%s: GetGlyphIndicesW failed", __FUNCTION__); - return false; - } - - for (int i = 0; i < actualLength; ++i) - glyphs->glyphs[i] = glyphIndices.at(i); - - *nglyphs = actualLength; - glyphs->numGlyphs = actualLength; - - if (!(flags & GlyphIndicesOnly)) - recalcAdvances(glyphs, {}); - - return true; -} - -QFontEngine::FaceId QWindowsFontEngineDirectWrite::faceId() const -{ - return m_faceId; -} - -void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const -{ - QVarLengthArray glyphIndices(glyphs->numGlyphs); - - // ### Caching? - for(int i=0; inumGlyphs; i++) - glyphIndices[i] = UINT16(glyphs->glyphs[i]); - - QVarLengthArray glyphMetrics(glyphIndices.size()); - - HRESULT hr; - DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); - if (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL) { - hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize), - 1.0f, - NULL, - TRUE, - glyphIndices.data(), - glyphIndices.size(), - glyphMetrics.data()); - } else { - hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(), - glyphIndices.size(), - glyphMetrics.data()); - } - if (SUCCEEDED(hr)) { - qreal stretch = fontDef.stretch != QFont::AnyStretch ? fontDef.stretch / 100.0 : 1.0; - for (int i = 0; i < glyphs->numGlyphs; ++i) - glyphs->advances[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth * stretch); - } else { - qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); - } -} - -void QWindowsFontEngineDirectWrite::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags) -{ - QVarLengthArray glyphIndices(nglyphs); - QVarLengthArray glyphOffsets(nglyphs); - QVarLengthArray glyphAdvances(nglyphs); - - for (int i=0; iGetGlyphRunOutline( - fontDef.pixelSize, - glyphIndices.data(), - glyphAdvances.data(), - glyphOffsets.data(), - nglyphs, - false, - flags & QTextItem::RightToLeft, - &geometrySink - ); - - if (FAILED(hr)) - qErrnoWarning("%s: GetGlyphRunOutline failed", __FUNCTION__); -} - -glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(const QGlyphLayout &glyphs) -{ - if (glyphs.numGlyphs == 0) - return glyph_metrics_t(); - QFixed w = 0; - 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); -} - -glyph_metrics_t QWindowsFontEngineDirectWrite::boundingBox(glyph_t g) -{ - UINT16 glyphIndex = g; - - DWRITE_GLYPH_METRICS glyphMetrics; - HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(&glyphIndex, 1, &glyphMetrics); - if (SUCCEEDED(hr)) { - QFixed advanceWidth = DESIGN_TO_LOGICAL(glyphMetrics.advanceWidth); - QFixed leftSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.leftSideBearing); - QFixed rightSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.rightSideBearing); - QFixed advanceHeight = DESIGN_TO_LOGICAL(glyphMetrics.advanceHeight); - QFixed verticalOriginY = DESIGN_TO_LOGICAL(glyphMetrics.verticalOriginY); - QFixed topSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.topSideBearing); - QFixed bottomSideBearing = DESIGN_TO_LOGICAL(glyphMetrics.bottomSideBearing); - QFixed width = advanceWidth - leftSideBearing - rightSideBearing; - QFixed height = advanceHeight - topSideBearing - bottomSideBearing; - return glyph_metrics_t(leftSideBearing, - -verticalOriginY + topSideBearing, - width, - height, - advanceWidth, - 0); - } else { - qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__); - } - - return glyph_metrics_t(); -} - -QFixed QWindowsFontEngineDirectWrite::capHeight() const -{ - if (m_capHeight <= 0) - return calculatedCapHeight(); - - return m_capHeight; -} - -QFixed QWindowsFontEngineDirectWrite::xHeight() const -{ - return m_xHeight; -} - -qreal QWindowsFontEngineDirectWrite::maxCharWidth() const -{ - return m_maxAdvanceWidth.toReal(); -} - -QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) -{ - QImage im = imageForGlyph(glyph, subPixelPosition, glyphMargin(Format_A8), t); - - QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8); - - for (int y=0; y(im.constScanLine(y)); - uchar *dst = alphaMap.scanLine(y); - for (int x=0; xpow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.); - ++dst; - ++src; - } - } - - return alphaMap; -} - -QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) -{ - return alphaMapForGlyph(glyph, subPixelPosition, QTransform()); -} - -bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const -{ - return true; -} - -QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, - QFixed subPixelPosition, - int margin, - const QTransform &originalTransform, - const QColor &color) -{ - UINT16 glyphIndex = t; - FLOAT glyphAdvance = 0; - - DWRITE_GLYPH_OFFSET glyphOffset; - glyphOffset.advanceOffset = 0; - glyphOffset.ascenderOffset = 0; - - DWRITE_GLYPH_RUN glyphRun; - glyphRun.fontFace = m_directWriteFontFace; - glyphRun.fontEmSize = fontDef.pixelSize; - glyphRun.glyphCount = 1; - glyphRun.glyphIndices = &glyphIndex; - glyphRun.glyphAdvances = &glyphAdvance; - glyphRun.isSideways = false; - glyphRun.bidiLevel = 0; - glyphRun.glyphOffsets = &glyphOffset; - - QTransform xform = originalTransform; - if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) - xform.scale(fontDef.stretch / 100.0, 1.0); - - DWRITE_MATRIX transform; - transform.dx = subPixelPosition.toReal(); - transform.dy = 0; - transform.m11 = xform.m11(); - transform.m12 = xform.m12(); - transform.m21 = xform.m21(); - transform.m22 = xform.m22(); - - DWRITE_RENDERING_MODE renderMode = - hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); - DWRITE_MEASURING_MODE measureMode = - renderModeToMeasureMode(renderMode); - - IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; - HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &glyphRun, - 1.0f, - &transform, - renderMode, - measureMode, - 0.0, 0.0, - &glyphAnalysis - ); - - if (SUCCEEDED(hr)) { - RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); - - if (rect.top == rect.bottom || rect.left == rect.right) - return QImage(); - - QRect boundingRect = QRect(QPoint(rect.left - margin, - rect.top - margin), - QPoint(rect.right + margin, - rect.bottom + margin)); - - - const int width = boundingRect.width() - 1; // -1 due to Qt's off-by-one definition of a QRect - const int height = boundingRect.height() - 1; - - QImage image; -#if defined(QT_USE_DIRECTWRITE2) - HRESULT hr = DWRITE_E_NOCOLOR; - IDWriteColorGlyphRunEnumerator *enumerator = 0; - IDWriteFactory2 *factory2 = nullptr; - if (glyphFormat == QFontEngine::Format_ARGB - && SUCCEEDED(m_fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory2), - reinterpret_cast(&factory2)))) { - hr = factory2->TranslateColorGlyphRun(0.0f, - 0.0f, - &glyphRun, - NULL, - measureMode, - NULL, - 0, - &enumerator); - image = QImage(width, height, QImage::Format_ARGB32_Premultiplied); - image.fill(0); - } else -#endif - { - image = QImage(width, height, QImage::Format_RGB32); - image.fill(0xffffffff); - } - -#if defined(QT_USE_DIRECTWRITE2) - BOOL ok = true; - - if (SUCCEEDED(hr)) { - while (SUCCEEDED(hr) && ok) { - const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun = 0; - hr = enumerator->GetCurrentRun(&colorGlyphRun); - if (FAILED(hr)) { // No colored runs, only outline - qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::GetCurrentRun failed", __FUNCTION__); - break; - } - - IDWriteGlyphRunAnalysis *colorGlyphsAnalysis = NULL; - hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &colorGlyphRun->glyphRun, - 1.0f, - &transform, - renderMode, - measureMode, - 0.0, 0.0, - &colorGlyphsAnalysis - ); - if (FAILED(hr)) { - qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed for color run", __FUNCTION__); - break; - } - - float r, g, b, a; - if (colorGlyphRun->paletteIndex == 0xFFFF) { - r = float(color.redF()); - g = float(color.greenF()); - b = float(color.blueF()); - a = float(color.alphaF()); - } else { - r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f); - g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f); - b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f); - a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f); - } - - if (!qFuzzyIsNull(a)) { - renderGlyphRun(&image, - r, - g, - b, - a, - colorGlyphsAnalysis, - boundingRect); - } - colorGlyphsAnalysis->Release(); - - hr = enumerator->MoveNext(&ok); - if (FAILED(hr)) { - qErrnoWarning(hr, "%s: IDWriteColorGlyphRunEnumerator::MoveNext failed", __FUNCTION__); - break; - } - } - } else -#endif - { - float r, g, b, a; - if (glyphFormat == QFontEngine::Format_ARGB) { - r = float(color.redF()); - g = float(color.greenF()); - b = float(color.blueF()); - a = float(color.alphaF()); - } else { - r = g = b = a = 0.0; - } - - renderGlyphRun(&image, - r, - g, - b, - a, - glyphAnalysis, - boundingRect); - } - - glyphAnalysis->Release(); - return image; - } else { - qErrnoWarning(hr, "%s: CreateGlyphRunAnalysis failed", __FUNCTION__); - return QImage(); - } -} - - -void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, - float r, - float g, - float b, - float a, - IDWriteGlyphRunAnalysis *glyphAnalysis, - const QRect &boundingRect) -{ - const int width = destination->width(); - const int height = destination->height(); - - r *= 255.0; - g *= 255.0; - b *= 255.0; - - const int size = width * height * 3; - if (size > 0) { - RECT rect; - rect.left = boundingRect.left(); - rect.top = boundingRect.top(); - rect.right = boundingRect.right(); - rect.bottom = boundingRect.bottom(); - - QVarLengthArray alphaValueArray(size); - BYTE *alphaValues = alphaValueArray.data(); - memset(alphaValues, 0, size); - - HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, - &rect, - alphaValues, - size); - if (SUCCEEDED(hr)) { - if (destination->hasAlphaChannel()) { - for (int y = 0; y < height; ++y) { - uint *dest = reinterpret_cast(destination->scanLine(y)); - BYTE *src = alphaValues + width * 3 * y; - - for (int x = 0; x < width; ++x) { - float redAlpha = a * *src++ / 255.0; - float greenAlpha = a * *src++ / 255.0; - float blueAlpha = a * *src++ / 255.0; - float averageAlpha = (redAlpha + greenAlpha + blueAlpha) / 3.0; - - QRgb currentRgb = dest[x]; - dest[x] = qRgba(qRound(qRed(currentRgb) * (1.0 - averageAlpha) + averageAlpha * r), - qRound(qGreen(currentRgb) * (1.0 - averageAlpha) + averageAlpha * g), - qRound(qBlue(currentRgb) * (1.0 - averageAlpha) + averageAlpha * b), - qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255)); - } - } - - } else { - for (int y = 0; y < height; ++y) { - uint *dest = reinterpret_cast(destination->scanLine(y)); - BYTE *src = alphaValues + width * 3 * y; - - for (int x = 0; x < width; ++x) { - dest[x] = *(src + 0) << 16 - | *(src + 1) << 8 - | *(src + 2); - - src += 3; - } - } - } - } else { - qErrnoWarning("%s: CreateAlphaTexture failed", __FUNCTION__); - } - } else { - glyphAnalysis->Release(); - qWarning("%s: Glyph has no bounds", __FUNCTION__); - } -} - -QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t, - QFixed subPixelPosition, - const QTransform &xform) -{ - QImage mask = imageForGlyph(t, - subPixelPosition, - glyphMargin(QFontEngine::Format_A32), - xform); - - return mask.depth() == 32 - ? mask - : mask.convertToFormat(QImage::Format_RGB32); -} - -QFontEngine *QWindowsFontEngineDirectWrite::cloneWithSize(qreal pixelSize) const -{ - QWindowsFontEngineDirectWrite *fontEngine = new QWindowsFontEngineDirectWrite(m_directWriteFontFace, - pixelSize, - m_fontEngineData); - - fontEngine->fontDef = fontDef; - fontEngine->fontDef.pixelSize = pixelSize; - if (!m_uniqueFamilyName.isEmpty()) { - fontEngine->setUniqueFamilyName(m_uniqueFamilyName); - QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase(); - static_cast(pfdb)->refUniqueFont(m_uniqueFamilyName); - } - - return fontEngine; -} - -Qt::HANDLE QWindowsFontEngineDirectWrite::handle() const -{ - return m_directWriteFontFace; -} - -void QWindowsFontEngineDirectWrite::initFontInfo(const QFontDef &request, - int dpi) -{ - fontDef = request; - - if (fontDef.pointSize < 0) - fontDef.pointSize = fontDef.pixelSize * 72. / dpi; - else if (fontDef.pixelSize == -1) - fontDef.pixelSize = qRound(fontDef.pointSize * dpi / 72.); -} - -QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyName) -{ - const QString substitute = - QWinRegistryKey(HKEY_LOCAL_MACHINE, - LR"(Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes)") - .stringValue(familyName); - return substitute.isEmpty() ? familyName : substitute; -} - -glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph, - QFixed subPixelPosition, - const QTransform &originalTransform, - GlyphFormat format) -{ - Q_UNUSED(format); - - QTransform matrix = originalTransform; - if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch) - matrix.scale(fontDef.stretch / 100.0, 1.0); - - glyph_metrics_t bbox = QFontEngine::boundingBox(glyph, matrix); // To get transformed advance - - UINT16 glyphIndex = glyph; - FLOAT glyphAdvance = 0; - - DWRITE_GLYPH_OFFSET glyphOffset; - glyphOffset.advanceOffset = 0; - glyphOffset.ascenderOffset = 0; - - DWRITE_GLYPH_RUN glyphRun; - glyphRun.fontFace = m_directWriteFontFace; - glyphRun.fontEmSize = fontDef.pixelSize; - glyphRun.glyphCount = 1; - glyphRun.glyphIndices = &glyphIndex; - glyphRun.glyphAdvances = &glyphAdvance; - glyphRun.isSideways = false; - glyphRun.bidiLevel = 0; - glyphRun.glyphOffsets = &glyphOffset; - - DWRITE_MATRIX transform; - transform.dx = subPixelPosition.toReal(); - transform.dy = 0; - transform.m11 = matrix.m11(); - transform.m12 = matrix.m12(); - transform.m21 = matrix.m21(); - transform.m22 = matrix.m22(); - - DWRITE_RENDERING_MODE renderMode = - hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference)); - DWRITE_MEASURING_MODE measureMode = renderModeToMeasureMode(renderMode); - - IDWriteGlyphRunAnalysis *glyphAnalysis = NULL; - HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis( - &glyphRun, - 1.0f, - &transform, - renderMode, - measureMode, - 0.0, 0.0, - &glyphAnalysis - ); - - if (SUCCEEDED(hr)) { - RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); - glyphAnalysis->Release(); - - int margin = glyphMargin(format); - - if (rect.left == rect.right || rect.top == rect.bottom) - return glyph_metrics_t(); - - return glyph_metrics_t(rect.left, - rect.top, - rect.right - rect.left + margin * 2, - rect.bottom - rect.top + margin * 2, - bbox.xoff, bbox.yoff); - } else { - return glyph_metrics_t(); - } -} - -QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color) -{ - return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_ARGB), t, color); -} - -QT_END_NAMESPACE - -#endif // QT_NO_DIRECTWRITE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h deleted file mode 100644 index 6e79190ce4..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h +++ /dev/null @@ -1,152 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSFONTENGINEDIRECTWRITE_H -#define QWINDOWSFONTENGINEDIRECTWRITE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#ifndef QT_NO_DIRECTWRITE - -#include -#include - -struct IDWriteFont; -struct IDWriteFontFace; -struct IDWriteFontFile; -struct IDWriteFactory; -struct IDWriteBitmapRenderTarget; -struct IDWriteGdiInterop; -struct IDWriteGlyphRunAnalysis; - -QT_BEGIN_NAMESPACE - -class QWindowsFontEngineData; - -class QWindowsFontEngineDirectWrite : public QFontEngine -{ - Q_DISABLE_COPY_MOVE(QWindowsFontEngineDirectWrite) -public: - explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace, - qreal pixelSize, - const QSharedPointer &d); - ~QWindowsFontEngineDirectWrite() override; - - void initFontInfo(const QFontDef &request, int dpi); - - QFixed lineThickness() const override; - QFixed underlinePosition() const override; - bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override; - 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; - void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags) const override; - - void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, - QPainterPath *path, QTextItem::RenderFlags flags) override; - - glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override; - glyph_metrics_t boundingBox(glyph_t g) override; - glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, - const QTransform &matrix, GlyphFormat) override; - - QFixed capHeight() const override; - QFixed xHeight() const override; - qreal maxCharWidth() const override; - FaceId faceId() const override; - - bool supportsSubPixelPositions() const override; - - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) override; - QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override; - QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override; - QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override; - - QFontEngine *cloneWithSize(qreal pixelSize) const override; - Qt::HANDLE handle() const override; - - const QSharedPointer &fontEngineData() const { return m_fontEngineData; } - - static QString fontNameSubstitute(const QString &familyName); - - IDWriteFontFace *directWriteFontFace() const { return m_directWriteFontFace; } - - void setUniqueFamilyName(const QString &newName) { m_uniqueFamilyName = newName; } - - void initializeHeightMetrics() const override; - -private: - QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, 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); - static QString filenameFromFontFile(IDWriteFontFile *fontFile); - - const QSharedPointer m_fontEngineData; - - IDWriteFontFace *m_directWriteFontFace; - IDWriteBitmapRenderTarget *m_directWriteBitmapRenderTarget; - - QFixed m_lineThickness; - QFixed m_underlinePosition; - int m_unitsPerEm; - QFixed m_capHeight; - QFixed m_xHeight; - QFixed m_maxAdvanceWidth; - FaceId m_faceId; - QString m_uniqueFamilyName; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_DIRECTWRITE - -#endif // QWINDOWSFONTENGINEDIRECTWRITE_H diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp deleted file mode 100644 index ad277ea7cd..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -#include "qwindowsnativeimage_p.h" - -#include -#include - -QT_BEGIN_NAMESPACE - -typedef struct { - BITMAPINFOHEADER bmiHeader; - DWORD redMask; - DWORD greenMask; - DWORD blueMask; -} BITMAPINFO_MASK; - -/*! - \class QWindowsNativeImage - \brief Windows Native image - - Note that size can be 0 (widget autotests with zero size), which - causes CreateDIBSection() to fail. - - \sa QWindowsBackingStore - \internal -*/ - -static inline HDC createDC() -{ - HDC display_dc = GetDC(0); - HDC hdc = CreateCompatibleDC(display_dc); - ReleaseDC(0, display_dc); - Q_ASSERT(hdc); - return hdc; -} - -static inline HBITMAP createDIB(HDC hdc, int width, int height, - QImage::Format format, - uchar **bitsIn) -{ - BITMAPINFO_MASK bmi; - memset(&bmi, 0, sizeof(bmi)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = -height; // top-down. - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biSizeImage = 0; - - if (format == QImage::Format_RGB16) { - bmi.bmiHeader.biBitCount = 16; - bmi.bmiHeader.biCompression = BI_BITFIELDS; - bmi.redMask = 0xF800; - bmi.greenMask = 0x07E0; - bmi.blueMask = 0x001F; - } else { - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.redMask = 0; - bmi.greenMask = 0; - bmi.blueMask = 0; - } - - uchar *bits = nullptr; - HBITMAP bitmap = CreateDIBSection(hdc, reinterpret_cast(&bmi), - DIB_RGB_COLORS, reinterpret_cast(&bits), 0, 0); - if (Q_UNLIKELY(!bitmap || !bits)) { - qFatal("%s: CreateDIBSection failed (%dx%d, format: %d)", __FUNCTION__, - width, height, int(format)); - } - - *bitsIn = bits; - return bitmap; -} - -QWindowsNativeImage::QWindowsNativeImage(int width, int height, - QImage::Format format) : - m_hdc(createDC()) -{ - if (width != 0 && height != 0) { - uchar *bits; - m_bitmap = createDIB(m_hdc, width, height, format, &bits); - m_null_bitmap = static_cast(SelectObject(m_hdc, m_bitmap)); - m_image = QImage(bits, width, height, format); - Q_ASSERT(m_image.paintEngine()->type() == QPaintEngine::Raster); - static_cast(m_image.paintEngine())->setDC(m_hdc); - } else { - m_image = QImage(width, height, format); - } - - GdiFlush(); -} - -QWindowsNativeImage::~QWindowsNativeImage() -{ - if (m_hdc) { - if (m_bitmap) { - if (m_null_bitmap) - SelectObject(m_hdc, m_null_bitmap); - DeleteObject(m_bitmap); - } - DeleteDC(m_hdc); - } -} - -QImage::Format QWindowsNativeImage::systemFormat() -{ - static int depth = -1; - if (depth == -1) { - if (HDC defaultDC = GetDC(0)) { - depth = GetDeviceCaps(defaultDC, BITSPIXEL); - ReleaseDC(0, defaultDC); - } else { - // FIXME Same remark as in QWindowsFontDatabase::defaultVerticalDPI() - // BONUS FIXME: Is 32 too generous/optimistic? - depth = 32; - } - } - return depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; -} - -QT_END_NAMESPACE diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h deleted file mode 100644 index ed68ac2644..0000000000 --- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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$ -** -****************************************************************************/ - -#ifndef QWINDOWSNATIVEIMAGE_H -#define QWINDOWSNATIVEIMAGE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QWindowsNativeImage -{ - Q_DISABLE_COPY_MOVE(QWindowsNativeImage) -public: - QWindowsNativeImage(int width, int height, - QImage::Format format); - - ~QWindowsNativeImage(); - - inline int width() const { return m_image.width(); } - inline int height() const { return m_image.height(); } - - QImage &image() { return m_image; } - const QImage &image() const { return m_image; } - - HDC hdc() const { return m_hdc; } - - static QImage::Format systemFormat(); - -private: - const HDC m_hdc; - QImage m_image; - - HBITMAP m_bitmap = 0; - HBITMAP m_null_bitmap = 0; -}; - -QT_END_NAMESPACE - -#endif // QWINDOWSNATIVEIMAGE_H diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri deleted file mode 100644 index c8466a1d2b..0000000000 --- a/src/platformsupport/fontdatabases/windows/windows.pri +++ /dev/null @@ -1,43 +0,0 @@ -QT *= gui-private - -SOURCES += \ - $$PWD/qwindowsfontdatabase.cpp \ - $$PWD/qwindowsfontdatabasebase.cpp \ - $$PWD/qwindowsfontengine.cpp \ - $$PWD/qwindowsnativeimage.cpp - -HEADERS += \ - $$PWD/qwindowsfontdatabase_p.h \ - $$PWD/qwindowsfontdatabasebase_p.h \ - $$PWD/qwindowsfontengine_p.h \ - $$PWD/qwindowsnativeimage_p.h - -qtConfig(freetype) { - SOURCES += $$PWD/qwindowsfontdatabase_ft.cpp - HEADERS += $$PWD/qwindowsfontdatabase_ft_p.h - QMAKE_USE_PRIVATE += freetype -} - -qtConfig(directwrite):qtConfig(direct2d) { - qtConfig(directwrite3) { - QMAKE_USE_PRIVATE += dwrite_3 - DEFINES *= QT_USE_DIRECTWRITE3 QT_USE_DIRECTWRITE2 - - SOURCES += $$PWD/qwindowsdirectwritefontdatabase.cpp - HEADERS += $$PWD/qwindowsdirectwritefontdatabase_p.h - } else: qtConfig(directwrite2) { - QMAKE_USE_PRIVATE += dwrite_2 - DEFINES *= QT_USE_DIRECTWRITE2 - } else { - QMAKE_USE_PRIVATE += dwrite - } - QMAKE_USE_PRIVATE += d2d1 - - SOURCES += $$PWD/qwindowsfontenginedirectwrite.cpp - HEADERS += $$PWD/qwindowsfontenginedirectwrite_p.h -} else { - DEFINES *= QT_NO_DIRECTWRITE -} - -QMAKE_USE_PRIVATE += advapi32 ole32 user32 gdi32 -mingw: QMAKE_USE_PRIVATE += uuid diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index cf41ffa116..1f8b41e7ec 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -1,8 +1,7 @@ TARGET = qdirect2d QT += \ - core-private gui-private \ - fontdatabase_support-private + core-private gui-private LIBS += -ldwmapi -lversion -ld3d11 -ldxgi -ldxguid QMAKE_USE_PRIVATE += gdi32 dwrite_1 d2d1_1 diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index 0172004de6..4ce5825f95 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -45,8 +45,7 @@ #include "qwindowsdirect2dbitmap.h" #include "qwindowsdirect2ddevicecontext.h" -#include -#include +#include #include "qwindowsintegration.h" #include diff --git a/src/plugins/platforms/minimal/.prev_CMakeLists.txt b/src/plugins/platforms/minimal/.prev_CMakeLists.txt index cdcdffa8e1..b5e165e2f1 100644 --- a/src/plugins/platforms/minimal/.prev_CMakeLists.txt +++ b/src/plugins/platforms/minimal/.prev_CMakeLists.txt @@ -26,7 +26,7 @@ qt_internal_add_plugin(QMinimalIntegrationPlugin ## Scopes: ##################################################################### -qt_extend_target(QMinimalIntegrationPlugin CONDITION NOT APPLE +qt_extend_target(QMinimalIntegrationPlugin CONDITION UNIX AND NOT APPLE PUBLIC_LIBRARIES Qt::FontDatabaseSupportPrivate ) diff --git a/src/plugins/platforms/minimal/CMakeLists.txt b/src/plugins/platforms/minimal/CMakeLists.txt index 72c1090771..958204bcd8 100644 --- a/src/plugins/platforms/minimal/CMakeLists.txt +++ b/src/plugins/platforms/minimal/CMakeLists.txt @@ -29,7 +29,7 @@ qt_internal_add_plugin(QMinimalIntegrationPlugin ## Scopes: ##################################################################### -qt_extend_target(QMinimalIntegrationPlugin CONDITION NOT APPLE +qt_extend_target(QMinimalIntegrationPlugin CONDITION UNIX AND NOT APPLE PUBLIC_LIBRARIES Qt::FontDatabaseSupportPrivate ) diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro index a644e65026..4eebd0f6ad 100644 --- a/src/plugins/platforms/minimal/minimal.pro +++ b/src/plugins/platforms/minimal/minimal.pro @@ -3,7 +3,7 @@ TARGET = qminimal QT += \ core-private gui-private -!darwin: QT += fontdatabase_support-private +!darwin:!win32: QT += fontdatabase_support-private DEFINES += QT_NO_FOREACH diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp index 16045d5e59..4a3b052200 100644 --- a/src/plugins/platforms/minimal/qminimalintegration.cpp +++ b/src/plugins/platforms/minimal/qminimalintegration.cpp @@ -47,9 +47,9 @@ #include #if defined(Q_OS_WIN) -# include +# include # if QT_CONFIG(freetype) -# include +# include # endif #elif defined(Q_OS_DARWIN) # include diff --git a/src/plugins/platforms/offscreen/.prev_CMakeLists.txt b/src/plugins/platforms/offscreen/.prev_CMakeLists.txt index a8643961d3..6ca250161f 100644 --- a/src/plugins/platforms/offscreen/.prev_CMakeLists.txt +++ b/src/plugins/platforms/offscreen/.prev_CMakeLists.txt @@ -27,7 +27,7 @@ qt_internal_add_plugin(QOffscreenIntegrationPlugin ## Scopes: ##################################################################### -qt_extend_target(QOffscreenIntegrationPlugin CONDITION NOT APPLE +qt_extend_target(QOffscreenIntegrationPlugin CONDITION UNIX AND NOT APPLE PUBLIC_LIBRARIES Qt::FontDatabaseSupportPrivate ) diff --git a/src/plugins/platforms/offscreen/CMakeLists.txt b/src/plugins/platforms/offscreen/CMakeLists.txt index 59bfb19fc9..a798344238 100644 --- a/src/plugins/platforms/offscreen/CMakeLists.txt +++ b/src/plugins/platforms/offscreen/CMakeLists.txt @@ -28,7 +28,7 @@ qt_internal_add_plugin(QOffscreenIntegrationPlugin ## Scopes: ##################################################################### -qt_extend_target(QOffscreenIntegrationPlugin CONDITION NOT APPLE +qt_extend_target(QOffscreenIntegrationPlugin CONDITION UNIX AND NOT APPLE PUBLIC_LIBRARIES Qt::FontDatabaseSupportPrivate ) diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index 0d6faf08a4..4bdbf7224a 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -3,7 +3,7 @@ TARGET = qoffscreen QT += \ core-private gui-private -!darwin: QT += fontdatabase_support-private +!darwin:!win32: QT += fontdatabase_support-private DEFINES += QT_NO_FOREACH diff --git a/src/plugins/platforms/windows/.prev_CMakeLists.txt b/src/plugins/platforms/windows/.prev_CMakeLists.txt index 3c1568ad53..84219ddcd8 100644 --- a/src/plugins/platforms/windows/.prev_CMakeLists.txt +++ b/src/plugins/platforms/windows/.prev_CMakeLists.txt @@ -50,7 +50,6 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin PUBLIC_LIBRARIES Qt::Core Qt::CorePrivate - Qt::FontDatabaseSupportPrivate Qt::Gui Qt::GuiPrivate dwmapi diff --git a/src/plugins/platforms/windows/CMakeLists.txt b/src/plugins/platforms/windows/CMakeLists.txt index 823ba613a3..9674710d54 100644 --- a/src/plugins/platforms/windows/CMakeLists.txt +++ b/src/plugins/platforms/windows/CMakeLists.txt @@ -51,7 +51,6 @@ qt_internal_add_plugin(QWindowsIntegrationPlugin PUBLIC_LIBRARIES Qt::Core Qt::CorePrivate - Qt::FontDatabaseSupportPrivate Qt::Gui Qt::GuiPrivate dwmapi diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index e3939ca2d7..e9d1915201 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -43,7 +43,7 @@ #include #include -#include +#include #include #include diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 2d014a7c07..9503d48bdb 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -49,11 +49,12 @@ #include "qwindowstheme.h" #include "qwindowsservices.h" #ifdef QT_USE_DIRECTWRITE3 -#include +#include #endif #ifndef QT_NO_FREETYPE -# include +# include #endif +#include #if QT_CONFIG(clipboard) # include "qwindowsclipboard.h" # if QT_CONFIG(draganddrop) diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 64cbda7c58..3c3763745c 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -43,7 +43,7 @@ #include #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index 0cd361516e..efd7d04b3e 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -54,7 +54,7 @@ #include #include #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 36831bdd81..1f4c851742 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -77,7 +77,7 @@ #include #include #include -#include +#include #include #include #include @@ -566,18 +566,23 @@ void QWindowsTheme::refresh() } #ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const LOGFONT &lf); // in platformsupport - QDebug operator<<(QDebug d, const NONCLIENTMETRICS &m) { QDebugStateSaver saver(d); d.nospace(); d.noquote(); d << "NONCLIENTMETRICS(iMenu=" << m.iMenuWidth << 'x' << m.iMenuHeight - << ", lfCaptionFont=" << m.lfCaptionFont << ", lfSmCaptionFont=" - << m.lfSmCaptionFont << ", lfMenuFont=" << m.lfMenuFont - << ", lfMessageFont=" << m.lfMessageFont << ", lfStatusFont=" - << m.lfStatusFont << ')'; + << ", lfCaptionFont="; + QWindowsFontDatabase::debugFormat(d, m.lfCaptionFont); + d << ", lfSmCaptionFont="; + QWindowsFontDatabase::debugFormat(d, m.lfSmCaptionFont); + d << ", lfMenuFont="; + QWindowsFontDatabase::debugFormat(d, m.lfMenuFont); + d << ", lfMessageFont="; + QWindowsFontDatabase::debugFormat(d, m.lfMessageFont); + d <<", lfStatusFont="; + QWindowsFontDatabase::debugFormat(d, m.lfStatusFont); + d << ')'; return d; } #endif // QT_NO_DEBUG_STREAM diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 258ffb0c0d..39a07e6361 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -1,8 +1,7 @@ TARGET = qwindows QT += \ - core-private gui-private \ - fontdatabase_support-private + core-private gui-private qtConfig(opengl): QT += opengl-private -- cgit v1.2.3