summaryrefslogtreecommitdiffstats
path: root/src/gui/text/windows/qwindowsfontdatabase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/windows/qwindowsfontdatabase.cpp')
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase.cpp397
1 files changed, 228 insertions, 169 deletions
diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp
index 4db0043b7f..adc06a6c2a 100644
--- a/src/gui/text/windows/qwindowsfontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabase.cpp
@@ -1,57 +1,23 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsfontdatabase_p.h"
-#include "qwindowsfontdatabase_ft_p.h" // for default font
+#ifndef QT_NO_FREETYPE
+# include "qwindowsfontdatabase_ft_p.h" // for default font
+#endif
#include "qwindowsfontengine_p.h"
#include <QtCore/qt_windows.h>
#include <QtGui/QFont>
#include <QtGui/QGuiApplication>
-#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtGui/private/qtgui-config_p.h>
#include <QtCore/qmath.h>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QtEndian>
-#include <QtCore/private/qsystemlibrary_p.h>
+#include <QtCore/QStandardPaths>
+#include <QtCore/private/qduplicatetracker_p.h>
#include <QtCore/private/qwinregistry_p.h>
#include <wchar.h>
@@ -65,13 +31,13 @@
# include "qwindowsfontenginedirectwrite_p.h"
#endif
-QT_BEGIN_NAMESPACE
+#include <mutex>
-#if QT_CONFIG(directwrite)
-// ### fixme: Consider direct linking of dwrite.dll once Windows Vista pre SP2 is dropped (QTBUG-49711)
+QT_BEGIN_NAMESPACE
-typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **);
+using namespace Qt::StringLiterals;
+#if QT_CONFIG(directwrite)
static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
const QString &familyName = QString(),
bool isColorFont = false)
@@ -82,7 +48,7 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
// At some scales, GDI will misrender the MingLiU font, so we force use of
// DirectWrite to work around the issue.
- if (Q_UNLIKELY(familyName.startsWith(QLatin1String("MingLiU"))))
+ if (Q_UNLIKELY(familyName.startsWith("MingLiU"_L1)))
return true;
if (isColorFont)
@@ -90,13 +56,14 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
return hintingPreference == QFont::PreferNoHinting
|| hintingPreference == QFont::PreferVerticalHinting
- || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting);
+ || (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting);
}
#endif // !QT_NO_DIRECTWRITE
/*!
- \struct QWindowsFontEngineData
+ \class QWindowsFontEngineData
\brief Static constant data shared by the font engines.
+ \internal
*/
QWindowsFontEngineData::QWindowsFontEngineData()
@@ -161,7 +128,7 @@ QDebug operator<<(QDebug d, const QFontDef &def)
QDebugStateSaver saver(d);
d.nospace();
d.noquote();
- d << "QFontDef(Family=\"" << def.family << '"';
+ d << "QFontDef(Family=\"" << def.families.first() << '"';
if (!def.styleName.isEmpty())
d << ", stylename=" << def.styleName;
d << ", pointsize=" << def.pointSize << ", pixelsize=" << def.pixelSize
@@ -224,17 +191,6 @@ static inline QFontDatabase::WritingSystem writingSystemFromCharSet(uchar charSe
return QFontDatabase::Any;
}
-#ifdef MAKE_TAG
-#undef MAKE_TAG
-#endif
-// GetFontData expects the tags in little endian ;(
-#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
- (((quint32)(ch4)) << 24) | \
- (((quint32)(ch3)) << 16) | \
- (((quint32)(ch2)) << 8) | \
- ((quint32)(ch1)) \
- )
-
bool qt_localizedName(const QString &name)
{
const QChar *c = name.unicode();
@@ -412,7 +368,7 @@ QString qt_getEnglishName(const QString &familyName, bool includeStyle)
HGDIOBJ oldobj = SelectObject( hdc, hfont );
- const DWORD name_tag = MAKE_TAG( 'n', 'a', 'm', 'e' );
+ const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
// get the name table
unsigned char *table = 0;
@@ -433,7 +389,7 @@ QString qt_getEnglishName(const QString &familyName, bool includeStyle)
const QFontNames names = qt_getCanonicalFontNames(table, bytes);
i18n_name = names.name;
if (includeStyle)
- i18n_name += QLatin1Char(' ') + names.style;
+ i18n_name += u' ' + names.style;
}
error:
delete [] table;
@@ -461,7 +417,7 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
// get the name table
QByteArray table;
- const DWORD name_tag = MAKE_TAG('n', 'a', 'm', 'e');
+ const DWORD name_tag = qFromBigEndian(QFont::Tag("name").value());
DWORD bytes = GetFontData(hdc, name_tag, 0, 0, 0);
if (bytes != GDI_ERROR) {
table.resize(bytes);
@@ -477,18 +433,6 @@ QFontNames qt_getCanonicalFontNames(const LOGFONT &lf)
return fontNames;
}
-static QChar *createFontFile(const QString &faceName)
-{
- QChar *faceNamePtr = nullptr;
- if (!faceName.isEmpty()) {
- const int nameLength = qMin(faceName.length(), LF_FACESIZE - 1);
- faceNamePtr = new QChar[nameLength + 1];
- memcpy(static_cast<void *>(faceNamePtr), faceName.utf16(), sizeof(wchar_t) * nameLength);
- faceNamePtr[nameLength] = 0;
- }
- return faceNamePtr;
-}
-
namespace {
struct StoreFontPayload {
StoreFontPayload(const QString &family,
@@ -498,7 +442,7 @@ namespace {
{}
QString populatedFontFamily;
- QSet<FontAndStyle> foundFontAndStyles;
+ QDuplicateTracker<FontAndStyle> foundFontAndStyles;
QWindowsFontDatabase *windowsFontDatabase;
};
}
@@ -512,7 +456,7 @@ static bool addFontToDatabase(QString familyName,
StoreFontPayload *sfp)
{
// the "@family" fonts are just the same as "family". Ignore them.
- if (familyName.isEmpty() || familyName.at(0) == QLatin1Char('@') || familyName.startsWith(QLatin1String("WST_")))
+ if (familyName.isEmpty() || familyName.at(0) == u'@' || familyName.startsWith("WST_"_L1))
return false;
uchar charSet = logFont.lfCharSet;
@@ -521,11 +465,13 @@ static bool addFontToDatabase(QString familyName,
const QString foundryName; // No such concept.
const bool fixed = !(textmetric->tmPitchAndFamily & TMPF_FIXED_PITCH);
const bool ttf = (textmetric->tmPitchAndFamily & TMPF_TRUETYPE);
- const bool scalable = textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE);
+ const bool unreliableTextMetrics = type == 0;
+ const bool scalable = (textmetric->tmPitchAndFamily & (TMPF_VECTOR|TMPF_TRUETYPE))
+ && !unreliableTextMetrics;
const int size = scalable ? SMOOTH_SCALABLE : textmetric->tmHeight;
const QFont::Style style = textmetric->tmItalic ? QFont::StyleItalic : QFont::StyleNormal;
const bool antialias = false;
- const QFont::Weight weight = QPlatformFontDatabase::weightFromInteger(textmetric->tmWeight);
+ const QFont::Weight weight = static_cast<QFont::Weight>(textmetric->tmWeight);
const QFont::Stretch stretch = QFont::Unstretched;
#ifndef QT_NO_DEBUG_OUTPUT
@@ -541,7 +487,7 @@ static bool addFontToDatabase(QString familyName,
str << " TRUETYPE";
str << " scalable=" << scalable << " Size=" << size
<< " Style=" << style << " Weight=" << weight
- << " stretch=" << stretch;
+ << " stretch=" << stretch << " styleName=" << styleName;
qCDebug(lcQpaFonts) << message;
}
#endif
@@ -559,7 +505,13 @@ static bool addFontToDatabase(QString familyName,
subFamilyStyle = styleName;
faceName = familyName; // Remember the original name for later lookups
familyName = canonicalNames.preferredName;
- styleName = canonicalNames.preferredStyle;
+ // Preferred style / typographic subfamily name:
+ // "If it is absent, then name ID 2 is considered to be the typographic subfamily name."
+ // From: https://docs.microsoft.com/en-us/windows/win32/directwrite/opentype-variable-fonts
+ // Name ID 2 is already stored in the styleName variable. Furthermore, for variable fonts,
+ // styleName holds the variation instance name, which should be used over name ID 2.
+ if (!canonicalNames.preferredStyle.isEmpty())
+ styleName = canonicalNames.preferredStyle;
}
QSupportedWritingSystems writingSystems;
@@ -579,7 +531,7 @@ static bool addFontToDatabase(QString familyName,
// display Thai text by default. As a temporary work around, we special case Segoe UI
// and remove the Thai script from its list of supported writing systems.
if (writingSystems.supported(QFontDatabase::Thai) &&
- familyName == QLatin1String("Segoe UI"))
+ familyName == "Segoe UI"_L1)
writingSystems.setSupported(QFontDatabase::Thai, false);
} else {
const QFontDatabase::WritingSystem ws = writingSystemFromCharSet(charSet);
@@ -587,33 +539,35 @@ static bool addFontToDatabase(QString familyName,
writingSystems.setSupported(ws);
}
- // We came here from populating a different font family, so we have
- // to ensure the entire typographic family is populated before we
- // mark it as such inside registerFont()
- if (!subFamilyName.isEmpty()
- && familyName != subFamilyName
- && sfp->populatedFontFamily != familyName
- && !QPlatformFontDatabase::isFamilyPopulated(familyName)) {
- sfp->windowsFontDatabase->populateFamily(familyName);
- }
-
+ const bool wasPopulated = QPlatformFontDatabase::isFamilyPopulated(familyName);
QPlatformFontDatabase::registerFont(familyName, styleName, foundryName, weight,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
+
// add fonts windows can generate for us:
if (weight <= QFont::DemiBold && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
if (style != QFont::StyleItalic && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, weight,
- QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
if (weight <= QFont::DemiBold && style != QFont::StyleItalic && styleName.isEmpty())
QPlatformFontDatabase::registerFont(familyName, QString(), foundryName, QFont::Bold,
- QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ QFont::StyleItalic, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
+
+ // We came here from populating a different font family, so we have
+ // to ensure the entire typographic family is populated before we
+ // mark it as such inside registerFont()
+ if (!subFamilyName.isEmpty()
+ && familyName != subFamilyName
+ && sfp->populatedFontFamily != familyName
+ && !wasPopulated) {
+ sfp->windowsFontDatabase->populateFamily(familyName);
+ }
if (!subFamilyName.isEmpty() && familyName != subFamilyName) {
QPlatformFontDatabase::registerFont(subFamilyName, subFamilyStyle, foundryName, weight,
- style, stretch, antialias, scalable, size, fixed, writingSystems, createFontFile(faceName));
+ style, stretch, antialias, scalable, size, fixed, writingSystems, new QWindowsFontDatabase::FontHandle(faceName));
}
if (!englishName.isEmpty() && englishName != familyName)
@@ -639,10 +593,8 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t
signature = &reinterpret_cast<const NEWTEXTMETRICEX *>(textmetric)->ntmFontSig;
// We get a callback for each script-type supported, but we register them all
// at once using the signature, so we only need one call to addFontToDatabase().
- FontAndStyle fontAndStyle = {familyName, styleName};
- if (sfp->foundFontAndStyles.contains(fontAndStyle))
+ if (sfp->foundFontAndStyles.hasSeen({familyName, styleName}))
return 1;
- sfp->foundFontAndStyles.insert(fontAndStyle);
}
addFontToDatabase(familyName, styleName, *logFont, textmetric, signature, type, sfp);
@@ -650,11 +602,26 @@ static int QT_WIN_CALLBACK storeFont(const LOGFONT *logFont, const TEXTMETRIC *t
return 1;
}
+bool QWindowsFontDatabase::populateFamilyAliases(const QString &missingFamily)
+{
+ Q_UNUSED(missingFamily);
+
+ if (m_hasPopulatedAliases)
+ return false;
+
+ QStringList families = QFontDatabase::families();
+ for (const QString &family : families)
+ populateFamily(family);
+ m_hasPopulatedAliases = true;
+
+ return true;
+}
+
void QWindowsFontDatabase::populateFamily(const QString &familyName)
{
qCDebug(lcQpaFonts) << familyName;
- if (familyName.size() >= LF_FACESIZE) {
- qCWarning(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\'';
+ if (familyName.size() >= LF_FACESIZE) { // Field length of LOGFONT::lfFaceName
+ qCDebug(lcQpaFonts) << "Unable to enumerate family '" << familyName << '\'';
return;
}
HDC dummy = GetDC(0);
@@ -688,24 +655,48 @@ static int QT_WIN_CALLBACK populateFontFamilies(const LOGFONT *logFont, const TE
return 1; // continue
}
+namespace {
+
+QString resolveFontPath(const QString &fontPath)
+{
+ if (fontPath.isEmpty())
+ return QString();
+
+ if (QFile::exists(fontPath))
+ return fontPath;
+
+ // resolve the path relatively to Windows Fonts directory
+ return QStandardPaths::locate(QStandardPaths::FontsLocation, fontPath);
+}
+
+}
+
void QWindowsFontDatabase::addDefaultEUDCFont()
{
const QString path = QWinRegistryKey(HKEY_CURRENT_USER, LR"(EUDC\1252)")
.stringValue(L"SystemDefaultEUDCFont");
- if (!path.isEmpty()) {
- QFile file(path);
- if (!file.open(QIODevice::ReadOnly)) {
- qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << path;
- return;
- }
+ if (path.isEmpty()) {
+ qCDebug(lcQpaFonts) << "There's no default EUDC font specified";
+ return;
+ }
- m_eudcFonts = addApplicationFont(file.readAll(), path);
+ const QString absolutePath = resolveFontPath(path);
+ if (absolutePath.isEmpty()) {
+ qCDebug(lcQpaFonts) << "Unable to locate default EUDC font:" << path;
+ return;
+ }
+
+ QFile file(absolutePath);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qCWarning(lcQpaFonts) << "Unable to open default EUDC font:" << absolutePath;
+ return;
}
+
+ m_eudcFonts = addApplicationFont(file.readAll(), absolutePath);
}
void QWindowsFontDatabase::populateFontDatabase()
{
- removeApplicationFonts();
HDC dummy = GetDC(0);
LOGFONT lf;
lf.lfCharSet = DEFAULT_CHARSET;
@@ -714,12 +705,18 @@ void QWindowsFontDatabase::populateFontDatabase()
EnumFontFamiliesEx(dummy, &lf, populateFontFamilies, 0, 0);
ReleaseDC(0, dummy);
// Work around EnumFontFamiliesEx() not listing the system font.
- QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().family();
+ const QString systemDefaultFamily = QWindowsFontDatabase::systemDefaultFont().families().constFirst();
if (QPlatformFontDatabase::resolveFontFamilyAlias(systemDefaultFamily) == systemDefaultFamily)
QPlatformFontDatabase::registerFontFamily(systemDefaultFamily);
addDefaultEUDCFont();
}
+void QWindowsFontDatabase::invalidate()
+{
+ QWindowsFontDatabaseBase::invalidate();
+ removeApplicationFonts();
+}
+
QWindowsFontDatabase::QWindowsFontDatabase()
{
// Properties accessed by QWin32PrintEngine (Qt Print Support)
@@ -742,7 +739,8 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- const QString faceName(static_cast<const QChar*>(handle));
+ FontHandle *fontHandle = static_cast<FontHandle *>(handle);
+ const QString faceName = fontHandle->faceName.left(LF_FACESIZE - 1);
QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
defaultVerticalDPI(),
data());
@@ -764,10 +762,10 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wstrict-aliasing")
- QString uniqueFamilyName = QLatin1Char('f')
- + QString::number(guid.Data1, 36) + QLatin1Char('-')
- + QString::number(guid.Data2, 36) + QLatin1Char('-')
- + QString::number(guid.Data3, 36) + QLatin1Char('-')
+ QString uniqueFamilyName = u'f'
+ + QString::number(guid.Data1, 36) + u'-'
+ + QString::number(guid.Data2, 36) + u'-'
+ + QString::number(guid.Data3, 36) + u'-'
+ QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
QT_WARNING_POP
@@ -791,7 +789,7 @@ QT_WARNING_POP
qWarning("%s: AddFontMemResourceEx failed", __FUNCTION__);
} else {
QFontDef request;
- request.family = uniqueFamilyName;
+ request.families = QStringList(uniqueFamilyName);
request.pixelSize = pixelSize;
request.styleStrategy = QFont::PreferMatch;
request.hintingPreference = hintingPreference;
@@ -802,9 +800,9 @@ QT_WARNING_POP
data());
if (fontEngine) {
- if (request.family != fontEngine->fontDef.family) {
- qWarning("%s: Failed to load font. Got fallback instead: %s",
- __FUNCTION__, qPrintable(fontEngine->fontDef.family));
+ if (request.families != fontEngine->fontDef.families) {
+ qWarning("%s: Failed to load font. Got fallback instead: %s", __FUNCTION__,
+ qPrintable(fontEngine->fontDef.families.constFirst()));
if (fontEngine->ref.loadRelaxed() == 0)
delete fontEngine;
fontEngine = 0;
@@ -815,12 +813,12 @@ QT_WARNING_POP
switch (fontEngine->type()) {
case QFontEngine::Win:
static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
- fontEngine->fontDef.family = actualFontName;
+ fontEngine->fontDef.families = QStringList(actualFontName);
break;
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
case QFontEngine::DirectWrite:
static_cast<QWindowsFontEngineDirectWrite *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
- fontEngine->fontDef.family = actualFontName;
+ fontEngine->fontDef.families = QStringList(actualFontName);
break;
#endif // directwrite && direct2d
@@ -828,10 +826,13 @@ QT_WARNING_POP
Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled font engine.");
}
- UniqueFontData uniqueData;
+ UniqueFontData uniqueData{};
uniqueData.handle = fontHandle;
- uniqueData.refCount.ref();
- m_uniqueFontData[uniqueFamilyName] = uniqueData;
+ ++uniqueData.refCount;
+ {
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ m_uniqueFontData[uniqueFamilyName] = uniqueData;
+ }
}
} else {
RemoveFontMemResourceEx(fontHandle);
@@ -852,36 +853,70 @@ QT_WARNING_POP
return fontEngine;
}
-static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData)
+static QList<quint32> getTrueTypeFontOffsets(const uchar *fontData, const uchar *fileEndSentinel)
{
QList<quint32> offsets;
- const quint32 headerTag = *reinterpret_cast<const quint32 *>(fontData);
- if (headerTag != MAKE_TAG('t', 't', 'c', 'f')) {
- if (headerTag != MAKE_TAG(0, 1, 0, 0)
- && headerTag != MAKE_TAG('O', 'T', 'T', 'O')
- && headerTag != MAKE_TAG('t', 'r', 'u', 'e')
- && headerTag != MAKE_TAG('t', 'y', 'p', '1'))
+ if (fileEndSentinel - fontData < 12) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ return offsets;
+ }
+
+ const quint32 headerTag = qFromUnaligned<quint32>(fontData);
+ if (headerTag != qFromBigEndian(QFont::Tag("ttcf").value())) {
+ if (headerTag != qFromBigEndian(QFont::Tag("\0\1\0\0").value())
+ && headerTag != qFromBigEndian(QFont::Tag("OTTO").value())
+ && headerTag != qFromBigEndian(QFont::Tag("true").value())
+ && headerTag != qFromBigEndian(QFont::Tag("typ1").value())) {
return offsets;
+ }
offsets << 0;
return offsets;
}
+
+ const quint32 maximumNumFonts = 0xffff;
const quint32 numFonts = qFromBigEndian<quint32>(fontData + 8);
- for (uint i = 0; i < numFonts; ++i) {
- offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+ if (numFonts > maximumNumFonts) {
+ qCWarning(lcQpaFonts) << "Font collection of" << numFonts << "fonts is too large. Aborting.";
+ return offsets;
}
+
+ if (quintptr(fileEndSentinel - fontData) > 12 + (numFonts - 1) * 4) {
+ for (quint32 i = 0; i < numFonts; ++i)
+ offsets << qFromBigEndian<quint32>(fontData + 12 + i * 4);
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ }
+
return offsets;
}
-static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
+static void getFontTable(const uchar *fileBegin, const uchar *fileEndSentinel, const uchar *data, quint32 tag, const uchar **table, quint32 *length)
{
- const quint16 numTables = qFromBigEndian<quint16>(data + 4);
- for (uint i = 0; i < numTables; ++i) {
- const quint32 offset = 12 + 16 * i;
- if (*reinterpret_cast<const quint32 *>(data + offset) == tag) {
- *table = fileBegin + qFromBigEndian<quint32>(data + offset + 8);
- *length = qFromBigEndian<quint32>(data + offset + 12);
- return;
+ if (fileEndSentinel - data >= 6) {
+ const quint16 numTables = qFromBigEndian<quint16>(data + 4);
+ if (fileEndSentinel - data >= 28 + 16 * (numTables - 1)) {
+ for (quint32 i = 0; i < numTables; ++i) {
+ const quint32 offset = 12 + 16 * i;
+ if (qFromUnaligned<quint32>(data + offset) == tag) {
+ const quint32 tableOffset = qFromBigEndian<quint32>(data + offset + 8);
+ if (quintptr(fileEndSentinel - fileBegin) <= tableOffset) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ break;
+ }
+ *table = fileBegin + tableOffset;
+ *length = qFromBigEndian<quint32>(data + offset + 12);
+ if (quintptr(fileEndSentinel - *table) < *length) {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
+ break;
+ }
+ return;
+ }
+ }
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
+ } else {
+ qCWarning(lcQpaFonts) << "Corrupted font data detected";
}
*table = 0;
*length = 0;
@@ -894,8 +929,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
QList<QFontValues> *values)
{
const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
+ const uchar *dataEndSentinel = data + fontData.size();
- QList<quint32> offsets = getTrueTypeFontOffsets(data);
+ QList<quint32> offsets = getTrueTypeFontOffsets(data, dataEndSentinel);
if (offsets.isEmpty())
return;
@@ -903,7 +939,9 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
const uchar *font = data + offsets.at(i);
const uchar *table;
quint32 length;
- getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length);
+ getFontTable(data, dataEndSentinel, font,
+ qFromBigEndian(QFont::Tag("name").value()),
+ &table, &length);
if (!table)
continue;
QFontNames names = qt_getCanonicalFontNames(table, length);
@@ -912,8 +950,11 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
families->append(std::move(names));
- if (values || signatures)
- getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
+ if (values || signatures) {
+ getFontTable(data, dataEndSentinel, font,
+ qFromBigEndian(QFont::Tag("OS/2").value()),
+ &table, &length);
+ }
if (values) {
QFontValues fontValues;
@@ -978,7 +1019,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
HDC hdc = GetDC(0);
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
- memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size()));
+ memcpy(lf.lfFaceName, familyName.data(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size()));
lf.lfCharSet = DEFAULT_CHARSET;
const QFontValues &values = fontValues.at(j);
lf.lfWeight = values.weight;
@@ -994,7 +1035,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
if (applicationFont != nullptr) {
QFontDatabasePrivate::ApplicationFont::Properties properties;
properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal;
- properties.weight = QPlatformFontDatabase::weightFromInteger(values.weight);
+ properties.weight = static_cast<int>(values.weight);
properties.familyName = familyName;
properties.styleName = styleName;
@@ -1041,7 +1082,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
QFontDatabasePrivate::ApplicationFont::Properties properties;
properties.style = values.isItalic ? QFont::StyleItalic : QFont::StyleNormal;
- properties.weight = QPlatformFontDatabase::weightFromInteger(values.weight);
+ properties.weight = static_cast<int>(values.weight);
properties.familyName = familyName;
properties.styleName = styleName;
@@ -1059,7 +1100,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
void QWindowsFontDatabase::removeApplicationFonts()
{
- for (const WinApplicationFont &font : qAsConst(m_applicationFonts)) {
+ for (const WinApplicationFont &font : std::as_const(m_applicationFonts)) {
if (font.handle) {
RemoveFontMemResourceEx(font.handle);
} else {
@@ -1071,10 +1112,22 @@ void QWindowsFontDatabase::removeApplicationFonts()
m_eudcFonts.clear();
}
+QWindowsFontDatabase::FontHandle::FontHandle(IDWriteFontFace *face, const QString &name)
+ : fontFace(face), faceName(name)
+{
+ fontFace->AddRef();
+}
+
+
+QWindowsFontDatabase::FontHandle::~FontHandle()
+{
+ if (fontFace != nullptr)
+ fontFace->Release();
+}
+
void QWindowsFontDatabase::releaseHandle(void *handle)
{
- const QChar *faceName = reinterpret_cast<const QChar *>(handle);
- delete[] faceName;
+ delete static_cast<FontHandle *>(handle);
}
QString QWindowsFontDatabase::fontDir() const
@@ -1091,18 +1144,22 @@ bool QWindowsFontDatabase::fontsAlwaysScalable() const
void QWindowsFontDatabase::derefUniqueFont(const QString &uniqueFont)
{
- if (m_uniqueFontData.contains(uniqueFont)) {
- if (!m_uniqueFontData[uniqueFont].refCount.deref()) {
- RemoveFontMemResourceEx(m_uniqueFontData[uniqueFont].handle);
- m_uniqueFontData.remove(uniqueFont);
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ const auto it = m_uniqueFontData.find(uniqueFont);
+ if (it != m_uniqueFontData.end()) {
+ if (--it->refCount == 0) {
+ RemoveFontMemResourceEx(it->handle);
+ m_uniqueFontData.erase(it);
}
}
}
void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
{
- if (m_uniqueFontData.contains(uniqueFont))
- m_uniqueFontData[uniqueFont].refCount.ref();
+ const std::scoped_lock lock(m_uniqueFontDataMutex);
+ const auto it = m_uniqueFontData.find(uniqueFont);
+ if (it != m_uniqueFontData.end())
+ ++it->refCount;
}
QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
@@ -1123,7 +1180,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
int dpi,
const QSharedPointer<QWindowsFontEngineData> &data)
{
- QFontEngine *fe = 0;
+ QFontEngine *fe = nullptr;
LOGFONT lf = fontDefToLOGFONT(request, faceName);
const bool preferClearTypeAA = lf.lfQuality == CLEARTYPE_QUALITY;
@@ -1152,7 +1209,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
if (nameSubstitute != fam) {
const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
- memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t));
+ memcpy(lf.lfFaceName, nameSubstitute.data(), nameSubstituteLength * sizeof(wchar_t));
lf.lfFaceName[nameSubstituteLength] = 0;
}
@@ -1170,6 +1227,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace);
if (SUCCEEDED(hr)) {
bool isColorFont = false;
+ bool needsSimulation = false;
#if QT_CONFIG(direct2d)
IDWriteFontFace2 *directWriteFontFace2 = nullptr;
if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2),
@@ -1177,13 +1235,17 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
if (directWriteFontFace2->IsColorFont())
isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0;
+ needsSimulation = directWriteFontFace2->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE;
+
directWriteFontFace2->Release();
}
#endif // direct2d
- useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont);
- qCDebug(lcQpaFonts) << __FUNCTION__ << request.family << request.pointSize
- << "pt" << "hintingPreference=" << hintingPreference << "color=" << isColorFont
- << dpi << "dpi" << "useDirectWrite=" << useDw;
+ useDw = useDw || useDirectWrite(hintingPreference, fam, isColorFont) || needsSimulation;
+ qCDebug(lcQpaFonts)
+ << __FUNCTION__ << request.families.first() << request.pointSize << "pt"
+ << "hintingPreference=" << hintingPreference << "color=" << isColorFont
+ << dpi << "dpi"
+ << "useDirectWrite=" << useDw;
if (useDw) {
QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
request.pixelSize,
@@ -1193,10 +1255,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
GetTextFace(data->hdc, 64, n);
QFontDef fontDef = request;
- fontDef.family = QString::fromWCharArray(n);
-
- if (isColorFont)
- fedw->glyphFormat = QFontEngine::Format_ARGB;
+ fontDef.families = QStringList(QString::fromWCharArray(n));
fedw->initFontInfo(fontDef, dpi);
fe = fedw;
}
@@ -1214,7 +1273,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
#endif // directwrite direct2d
if (!fe) {
- QWindowsFontEngine *few = new QWindowsFontEngine(request.family, lf, data);
+ QWindowsFontEngine *few = new QWindowsFontEngine(request.families.first(), lf, data);
if (preferClearTypeAA)
few->glyphFormat = QFontEngine::Format_A32;
few->initFontInfo(request, dpi);