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"
|
"-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": {
|
"drm": {
|
||||||
"label": "KMS",
|
"label": "KMS",
|
||||||
"test": {
|
"test": {
|
||||||
@ -1145,6 +1159,12 @@
|
|||||||
"condition": "libs.dwrite_1",
|
"condition": "libs.dwrite_1",
|
||||||
"output": [ "privateFeature" ]
|
"output": [ "privateFeature" ]
|
||||||
},
|
},
|
||||||
|
"directwrite3": {
|
||||||
|
"label": "DirectWrite 3",
|
||||||
|
"emitIf": "config.win32",
|
||||||
|
"condition": "features.directwrite1 && libs.dwrite_3",
|
||||||
|
"output": [ "privateFeature" ]
|
||||||
|
},
|
||||||
"directwrite2": {
|
"directwrite2": {
|
||||||
"label": "DirectWrite 2",
|
"label": "DirectWrite 2",
|
||||||
"emitIf": "config.win32",
|
"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
|
\li \c {dpiawareness=[0|1|2} Sets the DPI awareness of the process
|
||||||
(see \l{High DPI Displays}, since Qt 5.4).
|
(see \l{High DPI Displays}, since Qt 5.4).
|
||||||
\li \c {fontengine=freetype}, uses the FreeType font engine.
|
\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.
|
\li \c {menus=[native|none]}, controls the use of native menus.
|
||||||
|
|
||||||
Native menus are implemented using Win32 API and are simpler than
|
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/QDebug>
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
#include <QtCore/QtEndian>
|
#include <QtCore/QtEndian>
|
||||||
#include <QtCore/QThreadStorage>
|
|
||||||
#include <QtCore/private/qsystemlibrary_p.h>
|
#include <QtCore/private/qsystemlibrary_p.h>
|
||||||
#include <QtCore/private/qwinregistry_p.h>
|
#include <QtCore/private/qwinregistry_p.h>
|
||||||
|
|
||||||
@ -64,6 +63,7 @@
|
|||||||
# include <dwrite.h>
|
# include <dwrite.h>
|
||||||
# endif
|
# endif
|
||||||
# include <d2d1.h>
|
# include <d2d1.h>
|
||||||
|
# include "qwindowsdirectwritefontdatabase_p.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -75,40 +75,6 @@ Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
|
|||||||
|
|
||||||
typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **);
|
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,
|
static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
|
||||||
const QString &familyName = QString(),
|
const QString &familyName = QString(),
|
||||||
bool isColorFont = false)
|
bool isColorFont = false)
|
||||||
@ -131,459 +97,6 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
|
|||||||
}
|
}
|
||||||
#endif // !QT_NO_DIRECTWRITE
|
#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
|
\struct QWindowsFontEngineData
|
||||||
\brief Static constant data shared by the font engines.
|
\brief Static constant data shared by the font engines.
|
||||||
@ -620,18 +133,6 @@ unsigned QWindowsFontDatabase::fontOptions()
|
|||||||
return m_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()
|
qreal QWindowsFontDatabase::fontSmoothingGamma()
|
||||||
{
|
{
|
||||||
int winSmooth;
|
int winSmooth;
|
||||||
@ -645,26 +146,6 @@ qreal QWindowsFontDatabase::fontSmoothingGamma()
|
|||||||
return result;
|
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
|
\class QWindowsFontDatabase
|
||||||
\brief Font database for Windows
|
\brief Font database for Windows
|
||||||
@ -1239,20 +720,6 @@ void QWindowsFontDatabase::populateFontDatabase()
|
|||||||
addDefaultEUDCFont();
|
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()
|
QWindowsFontDatabase::QWindowsFontDatabase()
|
||||||
{
|
{
|
||||||
// Properties accessed by QWin32PrintEngine (Qt Print Support)
|
// Properties accessed by QWin32PrintEngine (Qt Print Support)
|
||||||
@ -1262,9 +729,9 @@ QWindowsFontDatabase::QWindowsFontDatabase()
|
|||||||
Q_UNUSED(logFontMetaTypeId)
|
Q_UNUSED(logFontMetaTypeId)
|
||||||
|
|
||||||
if (lcQpaFonts().isDebugEnabled()) {
|
if (lcQpaFonts().isDebugEnabled()) {
|
||||||
const QWindowsFontEngineDataPtr data = sharedFontData();
|
QSharedPointer<QWindowsFontEngineData> d = data();
|
||||||
qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: "
|
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));
|
const QString faceName(static_cast<const QChar*>(handle));
|
||||||
QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
|
QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
|
||||||
defaultVerticalDPI(),
|
defaultVerticalDPI(),
|
||||||
sharedFontData());
|
data());
|
||||||
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle;
|
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle;
|
||||||
return fe;
|
return fe;
|
||||||
}
|
}
|
||||||
@ -1332,7 +799,7 @@ QT_WARNING_POP
|
|||||||
|
|
||||||
fontEngine = QWindowsFontDatabase::createEngine(request, QString(),
|
fontEngine = QWindowsFontDatabase::createEngine(request, QString(),
|
||||||
defaultVerticalDPI(),
|
defaultVerticalDPI(),
|
||||||
sharedFontData());
|
data());
|
||||||
|
|
||||||
if (fontEngine) {
|
if (fontEngine) {
|
||||||
if (request.family != fontEngine->fontDef.family) {
|
if (request.family != fontEngine->fontDef.family) {
|
||||||
@ -1371,87 +838,17 @@ QT_WARNING_POP
|
|||||||
RemoveFontMemResourceEx(fontHandle);
|
RemoveFontMemResourceEx(fontHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get style and weight info
|
||||||
|
if (fontEngine != nullptr)
|
||||||
|
font.updateFromOS2Table(fontEngine);
|
||||||
}
|
}
|
||||||
#if !defined(QT_NO_DIRECTWRITE)
|
#if !defined(QT_NO_DIRECTWRITE)
|
||||||
else {
|
else {
|
||||||
CustomFontFileLoader fontFileLoader;
|
fontEngine = QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine;
|
||||||
return fontEngine;
|
return fontEngine;
|
||||||
}
|
}
|
||||||
@ -1683,14 +1080,6 @@ void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
|
|||||||
m_uniqueFontData[uniqueFont].refCount.ref();
|
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
|
// Creation functions
|
||||||
|
|
||||||
static const char *other_tryFonts[] = {
|
static const char *other_tryFonts[] = {
|
||||||
@ -1745,101 +1134,6 @@ static const char *kr_tryFonts[] = {
|
|||||||
|
|
||||||
static const char **tryFonts = 0;
|
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 QWindowsFontDatabase::extraTryFontsForFamily(const QString &family)
|
||||||
{
|
{
|
||||||
QStringList result;
|
QStringList result;
|
||||||
@ -1947,7 +1241,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(QT_NO_DIRECTWRITE)
|
#if !defined(QT_NO_DIRECTWRITE)
|
||||||
if (initDirectWrite(data.data())) {
|
if (data->directWriteFactory != nullptr) {
|
||||||
const QString fam = QString::fromWCharArray(lf.lfFaceName);
|
const QString fam = QString::fromWCharArray(lf.lfFaceName);
|
||||||
const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
|
const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
|
||||||
if (nameSubstitute != fam) {
|
if (nameSubstitute != fam) {
|
||||||
@ -2023,62 +1317,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
|
|||||||
return fe;
|
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
|
bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const
|
||||||
{
|
{
|
||||||
return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family);
|
return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family);
|
||||||
|
@ -51,39 +51,16 @@
|
|||||||
// We mean it.
|
// We mean it.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "qwindowsfontdatabasebase_p.h"
|
||||||
|
|
||||||
#include <qpa/qplatformfontdatabase.h>
|
#include <qpa/qplatformfontdatabase.h>
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QLoggingCategory>
|
#include <QtCore/QLoggingCategory>
|
||||||
#include <QtCore/qt_windows.h>
|
#include <QtCore/qt_windows.h>
|
||||||
|
|
||||||
#if !defined(QT_NO_DIRECTWRITE)
|
|
||||||
struct IDWriteFactory;
|
|
||||||
struct IDWriteGdiInterop;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts)
|
class QWindowsFontDatabase : public QWindowsFontDatabaseBase
|
||||||
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
Q_DISABLE_COPY_MOVE(QWindowsFontDatabase)
|
Q_DISABLE_COPY_MOVE(QWindowsFontDatabase)
|
||||||
public:
|
public:
|
||||||
@ -113,23 +90,15 @@ public:
|
|||||||
void refUniqueFont(const QString &uniqueFont);
|
void refUniqueFont(const QString &uniqueFont);
|
||||||
bool isPrivateFontFamily(const QString &family) const override;
|
bool isPrivateFontFamily(const QString &family) const override;
|
||||||
|
|
||||||
static QFont systemDefaultFont();
|
|
||||||
|
|
||||||
static QFontEngine *createEngine(const QFontDef &request, const QString &faceName,
|
static QFontEngine *createEngine(const QFontDef &request, const QString &faceName,
|
||||||
int dpi,
|
int dpi,
|
||||||
const QSharedPointer<QWindowsFontEngineData> &data);
|
const QSharedPointer<QWindowsFontEngineData> &data);
|
||||||
|
|
||||||
static HFONT systemFont();
|
|
||||||
static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0);
|
|
||||||
|
|
||||||
static qreal fontSmoothingGamma();
|
static qreal fontSmoothingGamma();
|
||||||
static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName);
|
|
||||||
|
|
||||||
static QStringList extraTryFontsForFamily(const QString &family);
|
static QStringList extraTryFontsForFamily(const QString &family);
|
||||||
static QString familyForStyleHint(QFont::StyleHint styleHint);
|
static QString familyForStyleHint(QFont::StyleHint styleHint);
|
||||||
|
|
||||||
static int defaultVerticalDPI();
|
|
||||||
|
|
||||||
static void setFontOptions(unsigned options);
|
static void setFontOptions(unsigned options);
|
||||||
static unsigned fontOptions();
|
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)
|
static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPreference hintingPreference)
|
||||||
{
|
{
|
||||||
if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting)
|
if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting)
|
||||||
@ -209,13 +221,10 @@ static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPref
|
|||||||
\ingroup qt-lighthouse-win
|
\ingroup qt-lighthouse-win
|
||||||
|
|
||||||
Font engine for subpixel positioned text on Windows Vista
|
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
|
configuration, the engine will be selected only when the hinting
|
||||||
preference of a font is set to None or Vertical hinting. The font
|
preference of a font is set to None or Vertical hinting, or
|
||||||
database uses most of the same logic but creates a direct write
|
when fontengine=directwrite is selected as platform option.
|
||||||
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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
|
QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
|
||||||
@ -480,9 +489,22 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
|
|||||||
glyphIndices[i] = UINT16(glyphs->glyphs[i]);
|
glyphIndices[i] = UINT16(glyphs->glyphs[i]);
|
||||||
|
|
||||||
QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
|
QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
|
||||||
HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
|
|
||||||
glyphIndices.size(),
|
HRESULT hr;
|
||||||
glyphMetrics.data());
|
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)) {
|
if (SUCCEEDED(hr)) {
|
||||||
qreal stretch = fontDef.stretch != QFont::AnyStretch ? fontDef.stretch / 100.0 : 1.0;
|
qreal stretch = fontDef.stretch != QFont::AnyStretch ? fontDef.stretch / 100.0 : 1.0;
|
||||||
for (int i = 0; i < glyphs->numGlyphs; ++i)
|
for (int i = 0; i < glyphs->numGlyphs; ++i)
|
||||||
@ -688,6 +710,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
|||||||
|
|
||||||
DWRITE_RENDERING_MODE renderMode =
|
DWRITE_RENDERING_MODE renderMode =
|
||||||
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
|
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
|
||||||
|
DWRITE_MEASURING_MODE measureMode =
|
||||||
|
renderModeToMeasureMode(renderMode);
|
||||||
|
|
||||||
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
|
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
|
||||||
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
|
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
|
||||||
@ -695,7 +719,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
|||||||
1.0f,
|
1.0f,
|
||||||
&transform,
|
&transform,
|
||||||
renderMode,
|
renderMode,
|
||||||
DWRITE_MEASURING_MODE_NATURAL,
|
measureMode,
|
||||||
0.0, 0.0,
|
0.0, 0.0,
|
||||||
&glyphAnalysis
|
&glyphAnalysis
|
||||||
);
|
);
|
||||||
@ -725,7 +749,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
|||||||
0.0f,
|
0.0f,
|
||||||
&glyphRun,
|
&glyphRun,
|
||||||
NULL,
|
NULL,
|
||||||
DWRITE_MEASURING_MODE_NATURAL,
|
measureMode,
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
&enumerator);
|
&enumerator);
|
||||||
@ -756,7 +780,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
|
|||||||
1.0f,
|
1.0f,
|
||||||
&transform,
|
&transform,
|
||||||
renderMode,
|
renderMode,
|
||||||
DWRITE_MEASURING_MODE_NATURAL,
|
measureMode,
|
||||||
0.0, 0.0,
|
0.0, 0.0,
|
||||||
&colorGlyphsAnalysis
|
&colorGlyphsAnalysis
|
||||||
);
|
);
|
||||||
@ -996,6 +1020,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
|
|||||||
|
|
||||||
DWRITE_RENDERING_MODE renderMode =
|
DWRITE_RENDERING_MODE renderMode =
|
||||||
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
|
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
|
||||||
|
DWRITE_MEASURING_MODE measureMode = renderModeToMeasureMode(renderMode);
|
||||||
|
|
||||||
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
|
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
|
||||||
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
|
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
|
||||||
@ -1003,7 +1028,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
|
|||||||
1.0f,
|
1.0f,
|
||||||
&transform,
|
&transform,
|
||||||
renderMode,
|
renderMode,
|
||||||
DWRITE_MEASURING_MODE_NATURAL,
|
measureMode,
|
||||||
0.0, 0.0,
|
0.0, 0.0,
|
||||||
&glyphAnalysis
|
&glyphAnalysis
|
||||||
);
|
);
|
||||||
|
@ -2,11 +2,13 @@ QT *= gui-private
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/qwindowsfontdatabase.cpp \
|
$$PWD/qwindowsfontdatabase.cpp \
|
||||||
|
$$PWD/qwindowsfontdatabasebase.cpp \
|
||||||
$$PWD/qwindowsfontengine.cpp \
|
$$PWD/qwindowsfontengine.cpp \
|
||||||
$$PWD/qwindowsnativeimage.cpp
|
$$PWD/qwindowsnativeimage.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
$$PWD/qwindowsfontdatabase_p.h \
|
$$PWD/qwindowsfontdatabase_p.h \
|
||||||
|
$$PWD/qwindowsfontdatabasebase_p.h \
|
||||||
$$PWD/qwindowsfontengine_p.h \
|
$$PWD/qwindowsfontengine_p.h \
|
||||||
$$PWD/qwindowsnativeimage_p.h
|
$$PWD/qwindowsnativeimage_p.h
|
||||||
|
|
||||||
@ -16,7 +18,13 @@ qtConfig(freetype) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
qtConfig(directwrite):qtConfig(direct2d) {
|
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
|
QMAKE_USE_PRIVATE += dwrite_2
|
||||||
DEFINES *= QT_USE_DIRECTWRITE2
|
DEFINES *= QT_USE_DIRECTWRITE2
|
||||||
} else {
|
} else {
|
||||||
|
@ -48,6 +48,9 @@
|
|||||||
#include "qwindowsscreen.h"
|
#include "qwindowsscreen.h"
|
||||||
#include "qwindowstheme.h"
|
#include "qwindowstheme.h"
|
||||||
#include "qwindowsservices.h"
|
#include "qwindowsservices.h"
|
||||||
|
#ifdef QT_USE_DIRECTWRITE3
|
||||||
|
#include <QtFontDatabaseSupport/private/qwindowsdirectwritefontdatabase_p.h>
|
||||||
|
#endif
|
||||||
#ifndef QT_NO_FREETYPE
|
#ifndef QT_NO_FREETYPE
|
||||||
# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h>
|
# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h>
|
||||||
#endif
|
#endif
|
||||||
@ -187,7 +190,9 @@ static inline unsigned parseOptions(const QStringList ¶mList,
|
|||||||
unsigned options = 0;
|
unsigned options = 0;
|
||||||
for (const QString ¶m : paramList) {
|
for (const QString ¶m : paramList) {
|
||||||
if (param.startsWith(u"fontengine=")) {
|
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;
|
options |= QWindowsIntegration::FontDatabaseFreeType;
|
||||||
} else if (param.endsWith(u"native")) {
|
} else if (param.endsWith(u"native")) {
|
||||||
options |= QWindowsIntegration::FontDatabaseNative;
|
options |= QWindowsIntegration::FontDatabaseNative;
|
||||||
@ -504,14 +509,17 @@ QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext()
|
|||||||
QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
|
QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
|
||||||
{
|
{
|
||||||
if (!d->m_fontDatabase) {
|
if (!d->m_fontDatabase) {
|
||||||
#ifdef QT_NO_FREETYPE
|
#ifdef QT_USE_DIRECTWRITE3
|
||||||
d->m_fontDatabase = new QWindowsFontDatabase();
|
if (d->m_options & QWindowsIntegration::FontDatabaseDirectWrite)
|
||||||
#else // QT_NO_FREETYPE
|
d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
#ifndef QT_NO_FREETYPE
|
||||||
if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
|
if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
|
||||||
d->m_fontDatabase = new QWindowsFontDatabaseFT;
|
d->m_fontDatabase = new QWindowsFontDatabaseFT;
|
||||||
else
|
else
|
||||||
d->m_fontDatabase = new QWindowsFontDatabase;
|
|
||||||
#endif // QT_NO_FREETYPE
|
#endif // QT_NO_FREETYPE
|
||||||
|
d->m_fontDatabase = new QWindowsFontDatabase();
|
||||||
}
|
}
|
||||||
return d->m_fontDatabase;
|
return d->m_fontDatabase;
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,8 @@ public:
|
|||||||
DetectAltGrModifier = 0x800,
|
DetectAltGrModifier = 0x800,
|
||||||
RtlEnabled = 0x1000,
|
RtlEnabled = 0x1000,
|
||||||
DarkModeWindowFrames = 0x2000,
|
DarkModeWindowFrames = 0x2000,
|
||||||
DarkModeStyle = 0x4000
|
DarkModeStyle = 0x4000,
|
||||||
|
FontDatabaseDirectWrite = 0x8000
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit QWindowsIntegration(const QStringList ¶mList);
|
explicit QWindowsIntegration(const QStringList ¶mList);
|
||||||
|
Loading…
Reference in New Issue
Block a user