Experimental DirectWrite font database
Adds an opt-in experimental DirectWrite-based font database. This cannot be the 100% replacement for GDI unfortunately, since quite a few font formats used on Windows are still unsupported. But it would be good to have it as an opt-in experimental feature since it should make it easier to solve multiple font selection issues we have on Windows. In order to still share the DirectWrite-specific code between the old and new database, this introduces a common base class. Note that the feature depends on DirectWrite 3 support (Windows 10). Fixes: QTBUG-74917 Change-Id: Ida08ec7ef4fda9fc78622ca4297909a727390a64 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
a13e8d6660
commit
35262678c3
@ -189,6 +189,20 @@
|
||||
"-ldwrite"
|
||||
]
|
||||
},
|
||||
"dwrite_3": {
|
||||
"label": "DirectWrite 3",
|
||||
"test": {
|
||||
"main": [
|
||||
"IUnknown *factory = 0;",
|
||||
"DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3),",
|
||||
" &factory);"
|
||||
]
|
||||
},
|
||||
"headers": "dwrite_3.h",
|
||||
"sources": [
|
||||
"-ldwrite"
|
||||
]
|
||||
},
|
||||
"drm": {
|
||||
"label": "KMS",
|
||||
"test": {
|
||||
@ -1145,6 +1159,12 @@
|
||||
"condition": "libs.dwrite_1",
|
||||
"output": [ "privateFeature" ]
|
||||
},
|
||||
"directwrite3": {
|
||||
"label": "DirectWrite 3",
|
||||
"emitIf": "config.win32",
|
||||
"condition": "features.directwrite1 && libs.dwrite_3",
|
||||
"output": [ "privateFeature" ]
|
||||
},
|
||||
"directwrite2": {
|
||||
"label": "DirectWrite 2",
|
||||
"emitIf": "config.win32",
|
||||
|
@ -613,6 +613,13 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
|
||||
\li \c {dpiawareness=[0|1|2} Sets the DPI awareness of the process
|
||||
(see \l{High DPI Displays}, since Qt 5.4).
|
||||
\li \c {fontengine=freetype}, uses the FreeType font engine.
|
||||
\li \c {fontengine=directwrite}, uses the experimental DirectWrite
|
||||
font database and defaults to using the DirectWrite font
|
||||
engine (which is otherwise only used for some font types
|
||||
or font properties.) This affects font selection and aims
|
||||
to provide font naming more consistent with other platforms,
|
||||
but does not support all font formats, such as Postscript
|
||||
Type-1 or Microsoft FNT fonts.
|
||||
\li \c {menus=[native|none]}, controls the use of native menus.
|
||||
|
||||
Native menus are implemented using Win32 API and are simpler than
|
||||
|
@ -0,0 +1,465 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <QtCore/qstringbuilder.h>
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
|
||||
#include <dwrite_3.h>
|
||||
#include <d2d1.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef QT_USE_DIRECTWRITE3
|
||||
|
||||
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<wchar_t> 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::UltraCondensed;
|
||||
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<void **>(&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;
|
||||
|
||||
QVarLengthArray<DWRITE_UNICODE_RANGE, 64> ranges(QFontDatabase::WritingSystemsCount);
|
||||
|
||||
uint count = 0;
|
||||
if (SUCCEEDED(font1->GetUnicodeRanges(QFontDatabase::WritingSystemsCount, ranges.data(), &count))) {
|
||||
// ###
|
||||
}
|
||||
QSupportedWritingSystems writingSystems;
|
||||
writingSystems.setSupported(QFontDatabase::Any);
|
||||
writingSystems.setSupported(QFontDatabase::Latin);
|
||||
|
||||
{
|
||||
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))) {
|
||||
if (!englishLocaleStyleName.isEmpty() || defaultLocaleStyleName.isEmpty()) {
|
||||
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<IDWriteFontFace *>(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
|
||||
{
|
||||
Q_UNUSED(styleHint);
|
||||
Q_UNUSED(script);
|
||||
|
||||
wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
|
||||
bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
|
||||
wchar_t englishLocale[] = L"en-us";
|
||||
|
||||
QStringList ret;
|
||||
|
||||
auto it = m_populatedFonts.find(family);
|
||||
IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr;
|
||||
if (fontFamily != nullptr) {
|
||||
IDWriteFontList *matchingFonts = nullptr;
|
||||
if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR,
|
||||
DWRITE_FONT_STRETCH_NORMAL,
|
||||
toDirectWriteStyle(style),
|
||||
&matchingFonts))) {
|
||||
for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) {
|
||||
IDWriteFont *font = nullptr;
|
||||
if (SUCCEEDED(matchingFonts->GetFont(j, &font))) {
|
||||
IDWriteFontFamily *fontFamily2;
|
||||
if (SUCCEEDED(font->GetFontFamily(&fontFamily2))) {
|
||||
IDWriteLocalizedStrings *names;
|
||||
if (SUCCEEDED(fontFamily2->GetFamilyNames(&names))) {
|
||||
QString name = localeString(names, englishLocale);
|
||||
if (name.isEmpty() && hasDefaultLocale)
|
||||
name = localeString(names, defaultLocale);
|
||||
|
||||
if (!name.isEmpty() && m_populatedFonts.contains(name))
|
||||
ret.append(name);
|
||||
|
||||
names->Release();
|
||||
}
|
||||
|
||||
fontFamily2->Release();
|
||||
}
|
||||
|
||||
font->Release();
|
||||
}
|
||||
}
|
||||
|
||||
matchingFonts->Release();
|
||||
}
|
||||
}
|
||||
|
||||
qDebug(lcQpaFonts) << "fallbacks for" << family << "is" << ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QStringList QWindowsDirectWriteFontDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName)
|
||||
{
|
||||
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<void **>(&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()) {
|
||||
ret.append(englishLocaleFamilyName);
|
||||
QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face);
|
||||
face->AddRef();
|
||||
}
|
||||
|
||||
if (!defaultLocaleFamilyName.isEmpty() && defaultLocaleFamilyName != englishLocaleFamilyName) {
|
||||
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<IDWriteFontFace *>(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
|
@ -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 <qpa/qplatformfontdatabase.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
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) 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<QString, IDWriteFontFamily *> m_populatedFonts;
|
||||
};
|
||||
|
||||
#endif // QT_USE_DIRECTWRITE3
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWINDOWSDIRECTWRITEFONTDATABASE_P_H
|
@ -51,7 +51,6 @@
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QtEndian>
|
||||
#include <QtCore/QThreadStorage>
|
||||
#include <QtCore/private/qsystemlibrary_p.h>
|
||||
#include <QtCore/private/qwinregistry_p.h>
|
||||
|
||||
@ -64,6 +63,7 @@
|
||||
# include <dwrite.h>
|
||||
# endif
|
||||
# include <d2d1.h>
|
||||
# include "qwindowsdirectwritefontdatabase_p.h"
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -75,40 +75,6 @@ Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
|
||||
|
||||
typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **);
|
||||
|
||||
static inline DWriteCreateFactoryType resolveDWriteCreateFactory()
|
||||
{
|
||||
QSystemLibrary library(QStringLiteral("dwrite"));
|
||||
QFunctionPointer result = library.resolve("DWriteCreateFactory");
|
||||
if (Q_UNLIKELY(!result)) {
|
||||
qWarning("Unable to load dwrite.dll");
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<DWriteCreateFactoryType>(result);
|
||||
}
|
||||
|
||||
static void createDirectWriteFactory(IDWriteFactory **factory)
|
||||
{
|
||||
*factory = nullptr;
|
||||
|
||||
static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory();
|
||||
if (!dWriteCreateFactory)
|
||||
return;
|
||||
|
||||
IUnknown *result = NULL;
|
||||
#if defined(QT_USE_DIRECTWRITE2)
|
||||
dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
|
||||
#endif
|
||||
|
||||
if (result == NULL) {
|
||||
if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
|
||||
qErrnoWarning("DWriteCreateFactory failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*factory = static_cast<IDWriteFactory *>(result);
|
||||
}
|
||||
|
||||
static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
|
||||
const QString &familyName = QString(),
|
||||
bool isColorFont = false)
|
||||
@ -131,459 +97,6 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
|
||||
}
|
||||
#endif // !QT_NO_DIRECTWRITE
|
||||
|
||||
// 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
|
||||
{
|
||||
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()
|
||||
|
||||
class EmbeddedFont
|
||||
{
|
||||
public:
|
||||
EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) {}
|
||||
|
||||
QString changeFamilyName(const QString &newFamilyName);
|
||||
QByteArray data() const { return m_fontData; }
|
||||
TableDirectory *tableDirectoryEntry(const QByteArray &tagName);
|
||||
QString familyName(TableDirectory *nameTableDirectory = 0);
|
||||
|
||||
private:
|
||||
QByteArray m_fontData;
|
||||
};
|
||||
|
||||
TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName)
|
||||
{
|
||||
Q_ASSERT(tagName.size() == 4);
|
||||
quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData()));
|
||||
const size_t fontDataSize = m_fontData.size();
|
||||
if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable)))
|
||||
return 0;
|
||||
|
||||
OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
|
||||
TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
|
||||
|
||||
const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables);
|
||||
if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount))
|
||||
return 0;
|
||||
|
||||
TableDirectory *tableDirectoryEnd = tableDirectory + tableCount;
|
||||
for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) {
|
||||
if (entry->identifier == tagId)
|
||||
return entry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry)
|
||||
{
|
||||
QString name;
|
||||
|
||||
if (nameTableDirectoryEntry == 0)
|
||||
nameTableDirectoryEntry = tableDirectoryEntry("name");
|
||||
|
||||
if (nameTableDirectoryEntry != 0) {
|
||||
quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset);
|
||||
if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable)))
|
||||
return QString();
|
||||
|
||||
NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data() + offset);
|
||||
NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
|
||||
|
||||
quint16 nameTableCount = qFromBigEndian<quint16>(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<quint16>(nameRecord->nameID) == 1
|
||||
&& qFromBigEndian<quint16>(nameRecord->platformID) == 3 // Windows
|
||||
&& qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) { // US English
|
||||
quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset);
|
||||
quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset);
|
||||
quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length);
|
||||
|
||||
if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength))
|
||||
return QString();
|
||||
|
||||
const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
|
||||
+ stringOffset
|
||||
+ nameOffset;
|
||||
|
||||
const quint16 *s = reinterpret_cast<const quint16 *>(ptr);
|
||||
const quint16 *e = s + nameLength / sizeof(quint16);
|
||||
while (s != e)
|
||||
name += QChar( qFromBigEndian<quint16>(*s++));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
QString EmbeddedFont::changeFamilyName(const QString &newFamilyName)
|
||||
{
|
||||
TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name");
|
||||
if (nameTableDirectoryEntry == 0)
|
||||
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<NameTable *>(newNameTable.data());
|
||||
nameTable->count = qbswap<quint16>(requiredRecordCount);
|
||||
nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
|
||||
|
||||
NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
|
||||
for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
|
||||
nameRecord->nameID = qbswap<quint16>(nameIds[i]);
|
||||
nameRecord->encodingID = qbswap<quint16>(1);
|
||||
nameRecord->languageID = qbswap<quint16>(0x0409);
|
||||
nameRecord->platformID = qbswap<quint16>(3);
|
||||
nameRecord->length = qbswap<quint16>(newFamilyNameSize);
|
||||
|
||||
// Special case for sub-family
|
||||
if (nameIds[i] == 4) {
|
||||
nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
|
||||
nameRecord->length = qbswap<quint16>(regularStringSize);
|
||||
}
|
||||
}
|
||||
|
||||
// nameRecord now points to string data
|
||||
quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord);
|
||||
const quint16 *sourceString = newFamilyName.utf16();
|
||||
for (int i = 0; i < newFamilyName.size(); ++i)
|
||||
stringStorage[i] = qbswap<quint16>(sourceString[i]);
|
||||
stringStorage += newFamilyName.size();
|
||||
|
||||
sourceString = regularString.utf16();
|
||||
for (int i = 0; i < regularString.size(); ++i)
|
||||
stringStorage[i] = qbswap<quint16>(sourceString[i]);
|
||||
}
|
||||
|
||||
quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
|
||||
quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
|
||||
|
||||
quint32 checkSum = 0;
|
||||
while (p < tableEnd)
|
||||
checkSum += qFromBigEndian<quint32>(*(p++));
|
||||
|
||||
nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
|
||||
nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
|
||||
nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
|
||||
|
||||
m_fontData.append(newNameTable);
|
||||
|
||||
return oldFamilyName;
|
||||
}
|
||||
|
||||
#if !defined(QT_NO_DIRECTWRITE)
|
||||
|
||||
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<const void *, QByteArray> 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<void * const *>(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() : m_directWriteFontFileLoader(nullptr)
|
||||
{
|
||||
createDirectWriteFactory(&m_directWriteFactory);
|
||||
|
||||
if (m_directWriteFactory) {
|
||||
m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
|
||||
m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
|
||||
}
|
||||
}
|
||||
|
||||
~CustomFontFileLoader()
|
||||
{
|
||||
if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0)
|
||||
m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
|
||||
|
||||
if (m_directWriteFactory != 0)
|
||||
m_directWriteFactory->Release();
|
||||
}
|
||||
|
||||
void addKey(const void *key, const QByteArray &fontData)
|
||||
{
|
||||
if (m_directWriteFontFileLoader != 0)
|
||||
m_directWriteFontFileLoader->addKey(key, fontData);
|
||||
}
|
||||
|
||||
void removeKey(const void *key)
|
||||
{
|
||||
if (m_directWriteFontFileLoader != 0)
|
||||
m_directWriteFontFileLoader->removeKey(key);
|
||||
}
|
||||
|
||||
IDWriteFontFileLoader *loader() const
|
||||
{
|
||||
return m_directWriteFontFileLoader;
|
||||
}
|
||||
|
||||
private:
|
||||
IDWriteFactory *m_directWriteFactory;
|
||||
DirectWriteFontFileLoader *m_directWriteFontFileLoader;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
/*!
|
||||
\struct QWindowsFontEngineData
|
||||
\brief Static constant data shared by the font engines.
|
||||
@ -620,18 +133,6 @@ unsigned QWindowsFontDatabase::fontOptions()
|
||||
return m_fontOptions;
|
||||
}
|
||||
|
||||
QWindowsFontEngineData::~QWindowsFontEngineData()
|
||||
{
|
||||
if (hdc)
|
||||
DeleteDC(hdc);
|
||||
#if !defined(QT_NO_DIRECTWRITE)
|
||||
if (directWriteGdiInterop)
|
||||
directWriteGdiInterop->Release();
|
||||
if (directWriteFactory)
|
||||
directWriteFactory->Release();
|
||||
#endif
|
||||
}
|
||||
|
||||
qreal QWindowsFontDatabase::fontSmoothingGamma()
|
||||
{
|
||||
int winSmooth;
|
||||
@ -645,26 +146,6 @@ qreal QWindowsFontDatabase::fontSmoothingGamma()
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(QT_NO_DIRECTWRITE)
|
||||
static inline bool initDirectWrite(QWindowsFontEngineData *d)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // !defined(QT_NO_DIRECTWRITE)
|
||||
|
||||
/*!
|
||||
\class QWindowsFontDatabase
|
||||
\brief Font database for Windows
|
||||
@ -1239,20 +720,6 @@ void QWindowsFontDatabase::populateFontDatabase()
|
||||
addDefaultEUDCFont();
|
||||
}
|
||||
|
||||
typedef QSharedPointer<QWindowsFontEngineData> QWindowsFontEngineDataPtr;
|
||||
|
||||
typedef QThreadStorage<QWindowsFontEngineDataPtr> FontEngineThreadLocalData;
|
||||
|
||||
Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
|
||||
|
||||
QSharedPointer<QWindowsFontEngineData> sharedFontData()
|
||||
{
|
||||
FontEngineThreadLocalData *data = fontEngineThreadLocalData();
|
||||
if (!data->hasLocalData())
|
||||
data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create());
|
||||
return data->localData();
|
||||
}
|
||||
|
||||
QWindowsFontDatabase::QWindowsFontDatabase()
|
||||
{
|
||||
// Properties accessed by QWin32PrintEngine (Qt Print Support)
|
||||
@ -1262,9 +729,9 @@ QWindowsFontDatabase::QWindowsFontDatabase()
|
||||
Q_UNUSED(logFontMetaTypeId)
|
||||
|
||||
if (lcQpaFonts().isDebugEnabled()) {
|
||||
const QWindowsFontEngineDataPtr data = sharedFontData();
|
||||
QSharedPointer<QWindowsFontEngineData> d = data();
|
||||
qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: "
|
||||
<< data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma;
|
||||
<< d->clearTypeEnabled << "gamma: " << d->fontSmoothingGamma;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1278,7 +745,7 @@ QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *ha
|
||||
const QString faceName(static_cast<const QChar*>(handle));
|
||||
QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
|
||||
defaultVerticalDPI(),
|
||||
sharedFontData());
|
||||
data());
|
||||
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle;
|
||||
return fe;
|
||||
}
|
||||
@ -1332,7 +799,7 @@ QT_WARNING_POP
|
||||
|
||||
fontEngine = QWindowsFontDatabase::createEngine(request, QString(),
|
||||
defaultVerticalDPI(),
|
||||
sharedFontData());
|
||||
data());
|
||||
|
||||
if (fontEngine) {
|
||||
if (request.family != fontEngine->fontDef.family) {
|
||||
@ -1371,87 +838,17 @@ QT_WARNING_POP
|
||||
RemoveFontMemResourceEx(fontHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// Get style and weight info
|
||||
if (fontEngine != nullptr)
|
||||
font.updateFromOS2Table(fontEngine);
|
||||
}
|
||||
#if !defined(QT_NO_DIRECTWRITE)
|
||||
else {
|
||||
CustomFontFileLoader fontFileLoader;
|
||||
fontFileLoader.addKey(this, fontData);
|
||||
|
||||
QSharedPointer<QWindowsFontEngineData> fontEngineData = sharedFontData();
|
||||
if (!initDirectWrite(fontEngineData.data()))
|
||||
return 0;
|
||||
|
||||
IDWriteFontFile *fontFile = 0;
|
||||
void *key = this;
|
||||
|
||||
HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
|
||||
sizeof(void *),
|
||||
fontFileLoader.loader(),
|
||||
&fontFile);
|
||||
if (FAILED(hres)) {
|
||||
qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 0;
|
||||
}
|
||||
|
||||
IDWriteFontFace *directWriteFontFace = 0;
|
||||
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 0;
|
||||
}
|
||||
|
||||
fontFile->Release();
|
||||
|
||||
fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
|
||||
pixelSize,
|
||||
fontEngineData);
|
||||
|
||||
// Get font family from font data
|
||||
fontEngine->fontDef.family = font.familyName();
|
||||
fontEngine->fontDef.hintingPreference = hintingPreference;
|
||||
|
||||
directWriteFontFace->Release();
|
||||
fontEngine = QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get style and weight info
|
||||
if (fontEngine != 0) {
|
||||
TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2");
|
||||
if (os2TableEntry != 0) {
|
||||
const OS2Table *os2Table =
|
||||
reinterpret_cast<const OS2Table *>(fontData.constData()
|
||||
+ qFromBigEndian<quint32>(os2TableEntry->offset));
|
||||
|
||||
bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
|
||||
bool oblique = qFromBigEndian<quint16>(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<quint16>(os2Table->weightClass));
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine;
|
||||
return fontEngine;
|
||||
}
|
||||
@ -1683,14 +1080,6 @@ void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
|
||||
m_uniqueFontData[uniqueFont].refCount.ref();
|
||||
}
|
||||
|
||||
// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont()
|
||||
HFONT QWindowsFontDatabase::systemFont()
|
||||
{
|
||||
static const auto stock_sysfont =
|
||||
reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
|
||||
return stock_sysfont;
|
||||
}
|
||||
|
||||
// Creation functions
|
||||
|
||||
static const char *other_tryFonts[] = {
|
||||
@ -1745,101 +1134,6 @@ static const char *kr_tryFonts[] = {
|
||||
|
||||
static const char **tryFonts = 0;
|
||||
|
||||
LOGFONT QWindowsFontDatabase::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) && sharedFontData()->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;
|
||||
}
|
||||
|
||||
QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family)
|
||||
{
|
||||
QStringList result;
|
||||
@ -1947,7 +1241,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
|
||||
}
|
||||
|
||||
#if !defined(QT_NO_DIRECTWRITE)
|
||||
if (initDirectWrite(data.data())) {
|
||||
if (data->directWriteFactory != nullptr) {
|
||||
const QString fam = QString::fromWCharArray(lf.lfFaceName);
|
||||
const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
|
||||
if (nameSubstitute != fam) {
|
||||
@ -2023,62 +1317,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
|
||||
return fe;
|
||||
}
|
||||
|
||||
QFont QWindowsFontDatabase::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(QWindowsFontDatabase::systemFont(), sizeof(lf), &lf);
|
||||
QFont systemFont = QWindowsFontDatabase::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;
|
||||
}
|
||||
|
||||
QFont QWindowsFontDatabase::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;
|
||||
}
|
||||
|
||||
int QWindowsFontDatabase::defaultVerticalDPI()
|
||||
{
|
||||
static int vDPI = -1;
|
||||
if (vDPI == -1) {
|
||||
if (HDC defaultDC = GetDC(0)) {
|
||||
vDPI = GetDeviceCaps(defaultDC, LOGPIXELSY);
|
||||
ReleaseDC(0, defaultDC);
|
||||
} else {
|
||||
// FIXME: Resolve now or return 96 and keep unresolved?
|
||||
vDPI = 96;
|
||||
}
|
||||
}
|
||||
return vDPI;
|
||||
}
|
||||
|
||||
bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const
|
||||
{
|
||||
return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family);
|
||||
|
@ -51,39 +51,16 @@
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "qwindowsfontdatabasebase_p.h"
|
||||
|
||||
#include <qpa/qplatformfontdatabase.h>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
#if !defined(QT_NO_DIRECTWRITE)
|
||||
struct IDWriteFactory;
|
||||
struct IDWriteGdiInterop;
|
||||
#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 QWindowsFontDatabase : public QPlatformFontDatabase
|
||||
class QWindowsFontDatabase : public QWindowsFontDatabaseBase
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(QWindowsFontDatabase)
|
||||
public:
|
||||
@ -113,23 +90,15 @@ public:
|
||||
void refUniqueFont(const QString &uniqueFont);
|
||||
bool isPrivateFontFamily(const QString &family) const override;
|
||||
|
||||
static QFont systemDefaultFont();
|
||||
|
||||
static QFontEngine *createEngine(const QFontDef &request, const QString &faceName,
|
||||
int dpi,
|
||||
const QSharedPointer<QWindowsFontEngineData> &data);
|
||||
|
||||
static HFONT systemFont();
|
||||
static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0);
|
||||
|
||||
static qreal fontSmoothingGamma();
|
||||
static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName);
|
||||
|
||||
static QStringList extraTryFontsForFamily(const QString &family);
|
||||
static QString familyForStyleHint(QFont::StyleHint styleHint);
|
||||
|
||||
static int defaultVerticalDPI();
|
||||
|
||||
static void setFontOptions(unsigned options);
|
||||
static unsigned fontOptions();
|
||||
|
||||
|
@ -0,0 +1,861 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <QtCore/private/qsystemlibrary_p.h>
|
||||
#include <QtCore/QThreadStorage>
|
||||
#include <QtCore/QtEndian>
|
||||
|
||||
#if !defined(QT_NO_DIRECTWRITE)
|
||||
# if defined(QT_USE_DIRECTWRITE3)
|
||||
# include <dwrite_3.h>
|
||||
# elif defined(QT_USE_DIRECTWRITE2)
|
||||
# include <dwrite_2.h>
|
||||
# else
|
||||
# include <dwrite.h>
|
||||
# endif
|
||||
# include <d2d1.h>
|
||||
# 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<const quint32 *>(tagName.constData()));
|
||||
const size_t fontDataSize = m_fontData.size();
|
||||
if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable)))
|
||||
return nullptr;
|
||||
|
||||
OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
|
||||
TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
|
||||
|
||||
const size_t tableCount = qFromBigEndian<quint16>(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<TableDirectory *>(directoryEntry);
|
||||
if (nameTableDirectoryEntry == nullptr)
|
||||
nameTableDirectoryEntry = static_cast<TableDirectory *>(tableDirectoryEntry("name"));
|
||||
|
||||
if (nameTableDirectoryEntry != nullptr) {
|
||||
quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset);
|
||||
if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable)))
|
||||
return QString();
|
||||
|
||||
NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data() + offset);
|
||||
NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
|
||||
|
||||
quint16 nameTableCount = qFromBigEndian<quint16>(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<quint16>(nameRecord->nameID) == 1
|
||||
&& qFromBigEndian<quint16>(nameRecord->platformID) == 3 // Windows
|
||||
&& qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) { // US English
|
||||
quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset);
|
||||
quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset);
|
||||
quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length);
|
||||
|
||||
if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength))
|
||||
return QString();
|
||||
|
||||
const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
|
||||
+ stringOffset
|
||||
+ nameOffset;
|
||||
|
||||
const quint16 *s = reinterpret_cast<const quint16 *>(ptr);
|
||||
const quint16 *e = s + nameLength / sizeof(quint16);
|
||||
while (s != e)
|
||||
name += QChar( qFromBigEndian<quint16>(*s++));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
void QWindowsFontDatabaseBase::EmbeddedFont::updateFromOS2Table(QFontEngine *fontEngine)
|
||||
{
|
||||
TableDirectory *os2TableEntry = static_cast<TableDirectory *>(tableDirectoryEntry("OS/2"));
|
||||
if (os2TableEntry != nullptr) {
|
||||
const OS2Table *os2Table =
|
||||
reinterpret_cast<const OS2Table *>(m_fontData.constData()
|
||||
+ qFromBigEndian<quint32>(os2TableEntry->offset));
|
||||
|
||||
bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
|
||||
bool oblique = qFromBigEndian<quint16>(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<quint16>(os2Table->weightClass));
|
||||
}
|
||||
}
|
||||
|
||||
QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(const QString &newFamilyName)
|
||||
{
|
||||
TableDirectory *nameTableDirectoryEntry = static_cast<TableDirectory *>(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<NameTable *>(newNameTable.data());
|
||||
nameTable->count = qbswap<quint16>(requiredRecordCount);
|
||||
nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
|
||||
|
||||
NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
|
||||
for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
|
||||
nameRecord->nameID = qbswap<quint16>(nameIds[i]);
|
||||
nameRecord->encodingID = qbswap<quint16>(1);
|
||||
nameRecord->languageID = qbswap<quint16>(0x0409);
|
||||
nameRecord->platformID = qbswap<quint16>(3);
|
||||
nameRecord->length = qbswap<quint16>(newFamilyNameSize);
|
||||
|
||||
// Special case for sub-family
|
||||
if (nameIds[i] == 4) {
|
||||
nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
|
||||
nameRecord->length = qbswap<quint16>(regularStringSize);
|
||||
}
|
||||
}
|
||||
|
||||
// nameRecord now points to string data
|
||||
quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord);
|
||||
const quint16 *sourceString = newFamilyName.utf16();
|
||||
for (int i = 0; i < newFamilyName.size(); ++i)
|
||||
stringStorage[i] = qbswap<quint16>(sourceString[i]);
|
||||
stringStorage += newFamilyName.size();
|
||||
|
||||
sourceString = regularString.utf16();
|
||||
for (int i = 0; i < regularString.size(); ++i)
|
||||
stringStorage[i] = qbswap<quint16>(sourceString[i]);
|
||||
}
|
||||
|
||||
quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
|
||||
quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
|
||||
|
||||
quint32 checkSum = 0;
|
||||
while (p < tableEnd)
|
||||
checkSum += qFromBigEndian<quint32>(*(p++));
|
||||
|
||||
nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
|
||||
nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
|
||||
nameTableDirectoryEntry->length = qbswap<quint32>(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<const void *, QByteArray> 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<void * const *>(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<QWindowsFontEngineData> QWindowsFontEngineDataPtr;
|
||||
typedef QThreadStorage<QWindowsFontEngineDataPtr> FontEngineThreadLocalData;
|
||||
Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
|
||||
|
||||
QSharedPointer<QWindowsFontEngineData> QWindowsFontDatabaseBase::data()
|
||||
{
|
||||
FontEngineThreadLocalData *data = fontEngineThreadLocalData();
|
||||
if (!data->hasLocalData())
|
||||
data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create());
|
||||
|
||||
if (!init(data->localData()))
|
||||
qCWarning(lcQpaFonts) << "Cannot initialize common font database data";
|
||||
|
||||
return data->localData();
|
||||
}
|
||||
|
||||
bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// ### Qt 6: Link directly to dwrite instead
|
||||
typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **);
|
||||
static inline DWriteCreateFactoryType resolveDWriteCreateFactory()
|
||||
{
|
||||
QSystemLibrary library(QStringLiteral("dwrite"));
|
||||
QFunctionPointer result = library.resolve("DWriteCreateFactory");
|
||||
if (Q_UNLIKELY(!result)) {
|
||||
qWarning("Unable to load dwrite.dll");
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<DWriteCreateFactoryType>(result);
|
||||
}
|
||||
|
||||
void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory)
|
||||
{
|
||||
*factory = nullptr;
|
||||
|
||||
static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory();
|
||||
if (!dWriteCreateFactory)
|
||||
return;
|
||||
|
||||
IUnknown *result = nullptr;
|
||||
#if 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<IDWriteFactory *>(result);
|
||||
}
|
||||
|
||||
int QWindowsFontDatabaseBase::defaultVerticalDPI()
|
||||
{
|
||||
static int vDPI = -1;
|
||||
if (vDPI == -1) {
|
||||
if (HDC defaultDC = GetDC(0)) {
|
||||
vDPI = GetDeviceCaps(defaultDC, LOGPIXELSY);
|
||||
ReleaseDC(0, defaultDC);
|
||||
} else {
|
||||
// FIXME: Resolve now or return 96 and keep unresolved?
|
||||
vDPI = 96;
|
||||
}
|
||||
}
|
||||
return vDPI;
|
||||
}
|
||||
|
||||
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<HFONT>(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<QWindowsFontEngineData> 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<QWindowsFontEngineData> 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();
|
||||
#endif // !defined(QT_NO_DIRECTWRITE)
|
||||
|
||||
return fontEngine;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -0,0 +1,131 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <qpa/qplatformfontdatabase.h>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/qt_windows.h>
|
||||
|
||||
#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 QSharedPointer<QWindowsFontEngineData> data();
|
||||
static void createDirectWriteFactory(IDWriteFactory **factory);
|
||||
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);
|
||||
|
||||
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<QWindowsFontEngineData> data);
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QWINDOWSFONTDATABASEBASE_P_H
|
@ -187,6 +187,18 @@ namespace {
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
@ -209,13 +221,10 @@ static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPref
|
||||
\ingroup qt-lighthouse-win
|
||||
|
||||
Font engine for subpixel positioned text on Windows Vista
|
||||
(with platform update) and Windows 7. If selected during
|
||||
(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. The font
|
||||
database uses most of the same logic but creates a direct write
|
||||
font based on the LOGFONT rather than a GDI handle.
|
||||
|
||||
Will probably be superseded by a common Free Type font engine in Qt 5.X.
|
||||
preference of a font is set to None or Vertical hinting, or
|
||||
when fontengine=directwrite is selected as platform option.
|
||||
*/
|
||||
|
||||
QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
|
||||
@ -480,9 +489,22 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
|
||||
glyphIndices[i] = UINT16(glyphs->glyphs[i]);
|
||||
|
||||
QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
|
||||
HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
|
||||
glyphIndices.size(),
|
||||
glyphMetrics.data());
|
||||
|
||||
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)
|
||||
@ -688,6 +710,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
||||
|
||||
DWRITE_RENDERING_MODE renderMode =
|
||||
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
|
||||
DWRITE_MEASURING_MODE measureMode =
|
||||
renderModeToMeasureMode(renderMode);
|
||||
|
||||
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
|
||||
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
|
||||
@ -695,7 +719,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
||||
1.0f,
|
||||
&transform,
|
||||
renderMode,
|
||||
DWRITE_MEASURING_MODE_NATURAL,
|
||||
measureMode,
|
||||
0.0, 0.0,
|
||||
&glyphAnalysis
|
||||
);
|
||||
@ -725,7 +749,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
||||
0.0f,
|
||||
&glyphRun,
|
||||
NULL,
|
||||
DWRITE_MEASURING_MODE_NATURAL,
|
||||
measureMode,
|
||||
NULL,
|
||||
0,
|
||||
&enumerator);
|
||||
@ -756,7 +780,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
||||
1.0f,
|
||||
&transform,
|
||||
renderMode,
|
||||
DWRITE_MEASURING_MODE_NATURAL,
|
||||
measureMode,
|
||||
0.0, 0.0,
|
||||
&colorGlyphsAnalysis
|
||||
);
|
||||
@ -996,6 +1020,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
|
||||
|
||||
DWRITE_RENDERING_MODE renderMode =
|
||||
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
|
||||
DWRITE_MEASURING_MODE measureMode = renderModeToMeasureMode(renderMode);
|
||||
|
||||
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
|
||||
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
|
||||
@ -1003,7 +1028,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
|
||||
1.0f,
|
||||
&transform,
|
||||
renderMode,
|
||||
DWRITE_MEASURING_MODE_NATURAL,
|
||||
measureMode,
|
||||
0.0, 0.0,
|
||||
&glyphAnalysis
|
||||
);
|
||||
|
@ -2,11 +2,13 @@ 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
|
||||
|
||||
@ -16,7 +18,13 @@ qtConfig(freetype) {
|
||||
}
|
||||
|
||||
qtConfig(directwrite):qtConfig(direct2d) {
|
||||
qtConfig(directwrite2) {
|
||||
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 {
|
||||
|
@ -48,6 +48,9 @@
|
||||
#include "qwindowsscreen.h"
|
||||
#include "qwindowstheme.h"
|
||||
#include "qwindowsservices.h"
|
||||
#ifdef QT_USE_DIRECTWRITE3
|
||||
#include <QtFontDatabaseSupport/private/qwindowsdirectwritefontdatabase_p.h>
|
||||
#endif
|
||||
#ifndef QT_NO_FREETYPE
|
||||
# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h>
|
||||
#endif
|
||||
@ -187,7 +190,9 @@ static inline unsigned parseOptions(const QStringList ¶mList,
|
||||
unsigned options = 0;
|
||||
for (const QString ¶m : paramList) {
|
||||
if (param.startsWith(u"fontengine=")) {
|
||||
if (param.endsWith(u"freetype")) {
|
||||
if (param.endsWith(u"directwrite")) {
|
||||
options |= QWindowsIntegration::FontDatabaseDirectWrite;
|
||||
} else if (param.endsWith(u"freetype")) {
|
||||
options |= QWindowsIntegration::FontDatabaseFreeType;
|
||||
} else if (param.endsWith(u"native")) {
|
||||
options |= QWindowsIntegration::FontDatabaseNative;
|
||||
@ -504,14 +509,17 @@ QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext()
|
||||
QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
|
||||
{
|
||||
if (!d->m_fontDatabase) {
|
||||
#ifdef QT_NO_FREETYPE
|
||||
d->m_fontDatabase = new QWindowsFontDatabase();
|
||||
#else // QT_NO_FREETYPE
|
||||
#ifdef QT_USE_DIRECTWRITE3
|
||||
if (d->m_options & QWindowsIntegration::FontDatabaseDirectWrite)
|
||||
d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
|
||||
else
|
||||
#endif
|
||||
#ifndef QT_NO_FREETYPE
|
||||
if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
|
||||
d->m_fontDatabase = new QWindowsFontDatabaseFT;
|
||||
else
|
||||
d->m_fontDatabase = new QWindowsFontDatabase;
|
||||
#endif // QT_NO_FREETYPE
|
||||
d->m_fontDatabase = new QWindowsFontDatabase();
|
||||
}
|
||||
return d->m_fontDatabase;
|
||||
}
|
||||
|
@ -72,7 +72,8 @@ public:
|
||||
DetectAltGrModifier = 0x800,
|
||||
RtlEnabled = 0x1000,
|
||||
DarkModeWindowFrames = 0x2000,
|
||||
DarkModeStyle = 0x4000
|
||||
DarkModeStyle = 0x4000,
|
||||
FontDatabaseDirectWrite = 0x8000
|
||||
};
|
||||
|
||||
explicit QWindowsIntegration(const QStringList ¶mList);
|
||||
|
Loading…
Reference in New Issue
Block a user