summaryrefslogtreecommitdiffstats
path: root/src/gui/text/windows/qwindowsfontdatabasebase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/windows/qwindowsfontdatabasebase.cpp')
-rw-r--r--src/gui/text/windows/qwindowsfontdatabasebase.cpp381
1 files changed, 213 insertions, 168 deletions
diff --git a/src/gui/text/windows/qwindowsfontdatabasebase.cpp b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
index 9a7c1c3578..84e619b0d9 100644
--- a/src/gui/text/windows/qwindowsfontdatabasebase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabasebase.cpp
@@ -1,46 +1,9 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the plugins of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwindowsfontdatabasebase_p.h"
#include "qwindowsfontdatabase_p.h"
-#include <QtCore/private/qsystemlibrary_p.h>
#include <QtCore/QThreadStorage>
#include <QtCore/QtEndian>
@@ -56,6 +19,8 @@
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
// Helper classes for creating font engines directly from font data
namespace {
@@ -275,14 +240,11 @@ QString QWindowsFontDatabaseBase::EmbeddedFont::changeFamilyName(const QString &
// nameRecord now points to string data
quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord);
- const quint16 *sourceString = newFamilyName.utf16();
- for (int i = 0; i < newFamilyName.size(); ++i)
- stringStorage[i] = qbswap<quint16>(sourceString[i]);
- stringStorage += newFamilyName.size();
+ for (QChar ch : newFamilyName)
+ *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
- sourceString = regularString.utf16();
- for (int i = 0; i < regularString.size(); ++i)
- stringStorage[i] = qbswap<quint16>(sourceString[i]);
+ for (QChar ch : regularString)
+ *stringStorage++ = qbswap<quint16>(quint16(ch.unicode()));
}
quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
@@ -317,15 +279,15 @@ namespace {
{
}
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
- ULONG STDMETHODCALLTYPE AddRef();
- ULONG STDMETHODCALLTYPE Release();
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object) override;
+ ULONG STDMETHODCALLTYPE AddRef() override;
+ ULONG STDMETHODCALLTYPE Release() override;
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);
+ UINT64 fragmentSize, OUT void **fragmentContext) override;
+ void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext) override;
+ HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize) override;
+ HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime) override;
private:
QByteArray m_fontData;
@@ -397,10 +359,10 @@ namespace {
{
}
- inline void addKey(const void *key, const QByteArray &fontData)
+ inline void addKey(const QByteArray &fontData)
{
- Q_ASSERT(!m_fontDatas.contains(key));
- m_fontDatas.insert(key, fontData);
+ if (!m_fontDatas.contains(fontData.data()))
+ m_fontDatas.insert(fontData.data(), fontData);
}
inline void removeKey(const void *key)
@@ -408,13 +370,18 @@ namespace {
m_fontDatas.remove(key);
}
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
- ULONG STDMETHODCALLTYPE AddRef();
- ULONG STDMETHODCALLTYPE Release();
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object) override;
+ ULONG STDMETHODCALLTYPE AddRef() override;
+ ULONG STDMETHODCALLTYPE Release() override;
HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
UINT32 fontFileReferenceKeySize,
- OUT IDWriteFontFileStream **fontFileStream);
+ OUT IDWriteFontFileStream **fontFileStream) override;
+
+ void clear()
+ {
+ m_fontDatas.clear();
+ }
private:
ULONG m_referenceCount;
@@ -473,52 +440,62 @@ namespace {
return S_OK;
}
- class CustomFontFileLoader
+} // Anonymous namespace
+
+class QCustomFontFileLoader
+{
+public:
+ QCustomFontFileLoader(IDWriteFactory *factory)
{
- public:
- CustomFontFileLoader(IDWriteFactory *factory)
- {
- m_directWriteFactory = factory;
+ m_directWriteFactory = factory;
- if (m_directWriteFactory) {
- m_directWriteFactory->AddRef();
+ if (m_directWriteFactory) {
+ m_directWriteFactory->AddRef();
- m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
- m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
- }
+ m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
+ m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
}
+ }
- ~CustomFontFileLoader()
- {
- if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
- m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
+ ~QCustomFontFileLoader()
+ {
+ clear();
- if (m_directWriteFactory != nullptr)
- m_directWriteFactory->Release();
- }
+ if (m_directWriteFactory != nullptr && m_directWriteFontFileLoader != nullptr)
+ m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
- void addKey(const void *key, const QByteArray &fontData)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->addKey(key, fontData);
- }
+ if (m_directWriteFactory != nullptr)
+ m_directWriteFactory->Release();
+ }
- void removeKey(const void *key)
- {
- if (m_directWriteFontFileLoader != nullptr)
- m_directWriteFontFileLoader->removeKey(key);
- }
+ void addKey(const QByteArray &fontData)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->addKey(fontData);
+ }
- IDWriteFontFileLoader *loader() const
- {
- return m_directWriteFontFileLoader;
- }
+ void removeKey(const void *key)
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->removeKey(key);
+ }
+
+ IDWriteFontFileLoader *loader() const
+ {
+ return m_directWriteFontFileLoader;
+ }
+
+ void clear()
+ {
+ if (m_directWriteFontFileLoader != nullptr)
+ m_directWriteFontFileLoader->clear();
+ }
+
+private:
+ IDWriteFactory *m_directWriteFactory = nullptr;
+ DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
+};
- private:
- IDWriteFactory *m_directWriteFactory = nullptr;
- DirectWriteFontFileLoader *m_directWriteFontFileLoader = nullptr;
- };
-} // Anonymous namespace
#endif // directwrite && direct2d
@@ -582,36 +559,34 @@ bool QWindowsFontDatabaseBase::init(QSharedPointer<QWindowsFontEngineData> d)
}
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
-// ### Qt 6: Link directly to dwrite instead
-typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **);
-static inline DWriteCreateFactoryType resolveDWriteCreateFactory()
-{
- QSystemLibrary library(QStringLiteral("dwrite"));
- QFunctionPointer result = library.resolve("DWriteCreateFactory");
- if (Q_UNLIKELY(!result)) {
- qWarning("Unable to load dwrite.dll");
- return nullptr;
- }
- return reinterpret_cast<DWriteCreateFactoryType>(result);
-}
-
void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory)
{
*factory = nullptr;
-
- static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory();
- if (!dWriteCreateFactory)
- return;
-
IUnknown *result = nullptr;
+
# if QT_CONFIG(directwrite3)
- dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory6";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory6), &result);
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory5";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), &result);
+ }
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory3";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3), &result);
+ }
# endif
- if (result == nullptr)
- dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
if (result == nullptr) {
- if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
+ qCDebug(lcQpaFonts) << "Trying to create IDWriteFactory2";
+ DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
+ }
+
+ if (result == nullptr) {
+ qCDebug(lcQpaFonts) << "Trying to create plain IDWriteFactory";
+ if (FAILED(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
qErrnoWarning("DWriteCreateFactory failed");
return;
}
@@ -621,16 +596,9 @@ void QWindowsFontDatabaseBase::createDirectWriteFactory(IDWriteFactory **factory
}
#endif // directwrite && direct2d
-static int s_defaultVerticalDPI = 96; // Native Pixels
-
int QWindowsFontDatabaseBase::defaultVerticalDPI()
{
- return s_defaultVerticalDPI;
-}
-
-void QWindowsFontDatabaseBase::setDefaultVerticalDPI(int d)
-{
- s_defaultVerticalDPI = d;
+ return 96;
}
LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName)
@@ -707,22 +675,12 @@ LOGFONT QWindowsFontDatabaseBase::fontDefToLOGFONT(const QFontDef &request, cons
QString fam = faceName;
if (fam.isEmpty())
- fam = request.families.size() > 0 ? request.families.at(0) : request.family;
+ fam = request.families.first();
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;
@@ -755,36 +713,55 @@ HFONT QWindowsFontDatabaseBase::systemFont()
QFont QWindowsFontDatabaseBase::systemDefaultFont()
{
// Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610)
- NONCLIENTMETRICS ncm;
- ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
- SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
+ NONCLIENTMETRICS ncm = {};
+ ncm.cbSize = sizeof(ncm);
+ SystemParametersInfoForDpi(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0, defaultVerticalDPI());
const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont;
return systemFont;
}
+void QWindowsFontDatabaseBase::invalidate()
+{
+#if QT_CONFIG(directwrite)
+ m_fontFileLoader.reset(nullptr);
+#endif
+}
+
#if QT_CONFIG(directwrite) && QT_CONFIG(direct2d)
-IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData) const
+IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArray &fontData)
+{
+ QList<IDWriteFontFace *> faces = createDirectWriteFaces(fontData, false);
+ Q_ASSERT(faces.size() <= 1);
+
+ return faces.isEmpty() ? nullptr : faces.first();
+}
+
+QList<IDWriteFontFace *> QWindowsFontDatabaseBase::createDirectWriteFaces(const QByteArray &fontData,
+ bool queryVariations) const
{
+ QList<IDWriteFontFace *> ret;
QSharedPointer<QWindowsFontEngineData> fontEngineData = data();
if (fontEngineData->directWriteFactory == nullptr) {
qCWarning(lcQpaFonts) << "DirectWrite factory not created in QWindowsFontDatabaseBase::createDirectWriteFace()";
- return nullptr;
+ return ret;
}
- CustomFontFileLoader fontFileLoader(fontEngineData->directWriteFactory);
- fontFileLoader.addKey(this, fontData);
+ if (m_fontFileLoader == nullptr)
+ m_fontFileLoader.reset(new QCustomFontFileLoader(fontEngineData->directWriteFactory));
+
+ m_fontFileLoader->addKey(fontData);
IDWriteFontFile *fontFile = nullptr;
- const void *key = this;
+ const void *key = fontData.data();
HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
sizeof(void *),
- fontFileLoader.loader(),
+ m_fontFileLoader->loader(),
&fontFile);
if (FAILED(hres)) {
qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
- return nullptr;
+ return ret;
}
BOOL isSupportedFontType;
@@ -794,28 +771,75 @@ IDWriteFontFace *QWindowsFontDatabaseBase::createDirectWriteFace(const QByteArra
fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
if (!isSupportedFontType) {
fontFile->Release();
- return nullptr;
+ return ret;
+ }
+
+#if QT_CONFIG(directwrite3)
+ IDWriteFactory5 *factory5 = nullptr;
+ if (queryVariations && SUCCEEDED(fontEngineData->directWriteFactory->QueryInterface(__uuidof(IDWriteFactory5),
+ reinterpret_cast<void **>(&factory5)))) {
+
+ IDWriteFontSetBuilder1 *builder;
+ if (SUCCEEDED(factory5->CreateFontSetBuilder(&builder))) {
+ if (SUCCEEDED(builder->AddFontFile(fontFile))) {
+ IDWriteFontSet *fontSet;
+ if (SUCCEEDED(builder->CreateFontSet(&fontSet))) {
+ int count = fontSet->GetFontCount();
+ qCDebug(lcQpaFonts) << "Found" << count << "variations in font file";
+ for (int i = 0; i < count; ++i) {
+ IDWriteFontFaceReference *ref;
+ if (SUCCEEDED(fontSet->GetFontFaceReference(i, &ref))) {
+ IDWriteFontFace3 *face;
+ if (SUCCEEDED(ref->CreateFontFace(&face))) {
+ ret.append(face);
+ }
+ ref->Release();
+ }
+ }
+ fontSet->Release();
+ }
+ }
+
+ builder->Release();
+ }
+
+ factory5->Release();
}
+#else
+ Q_UNUSED(queryVariations);
+#endif
// ### Currently no support for .ttc, but we could easily return a list here.
- IDWriteFontFace *directWriteFontFace = nullptr;
- hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
- 1,
- &fontFile,
- 0,
- DWRITE_FONT_SIMULATIONS_NONE,
- &directWriteFontFace);
- if (FAILED(hres)) {
- qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
- fontFile->Release();
- return nullptr;
+ if (ret.isEmpty()) {
+ IDWriteFontFace *directWriteFontFace = nullptr;
+ hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
+ 1,
+ &fontFile,
+ 0,
+ DWRITE_FONT_SIMULATIONS_NONE,
+ &directWriteFontFace);
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
+ fontFile->Release();
+ return ret;
+ } else {
+ ret.append(directWriteFontFace);
+ }
}
fontFile->Release();
- return directWriteFontFace;
+
+ return ret;
}
#endif // directwrite && direct2d
+QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QFontDef &fontDef, void *handle)
+{
+ // This function was apparently not used before, and probably isn't now either,
+ // call the base implementation which just prints that it's not supported.
+ return QPlatformFontDatabase::fontEngine(fontDef, handle);
+}
+
QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
{
QFontEngine *fontEngine = nullptr;
@@ -825,7 +849,10 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr
if (fontEngineData->directWriteFactory == nullptr)
return nullptr;
- IDWriteFontFace *directWriteFontFace = createDirectWriteFace(fontData);
+ IDWriteFontFace * directWriteFontFace = createDirectWriteFace(fontData);
+ if (directWriteFontFace == nullptr)
+ return nullptr;
+
fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
pixelSize,
fontEngineData);
@@ -833,7 +860,7 @@ QFontEngine *QWindowsFontDatabaseBase::fontEngine(const QByteArray &fontData, qr
// Get font family from font data
EmbeddedFont font(fontData);
font.updateFromOS2Table(fontEngine);
- fontEngine->fontDef.family = font.familyName();
+ fontEngine->fontDef.families = QStringList(font.familyName());
fontEngine->fontDef.hintingPreference = hintingPreference;
directWriteFontFace->Release();
@@ -867,7 +894,7 @@ QString QWindowsFontDatabaseBase::familyForStyleHint(QFont::StyleHint styleHint)
default:
break;
}
- return QStringLiteral("MS Shell Dlg 2");
+ return QStringLiteral("Tahoma");
}
// Creation functions
@@ -883,6 +910,7 @@ static const char *other_tryFonts[] = {
};
static const char *jp_tryFonts [] = {
+ "Yu Gothic UI",
"MS UI Gothic",
"Arial",
"Gulim",
@@ -927,8 +955,7 @@ static const char **tryFonts = nullptr;
QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &family)
{
QStringList result;
- QFontDatabase db;
- if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) {
+ if (!QFontDatabase::writingSystems(family).contains(QFontDatabase::Symbol)) {
if (!tryFonts) {
LANGID lid = GetUserDefaultLangID();
switch (lid&0xff) {
@@ -949,13 +976,12 @@ QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &fami
break;
}
}
- QFontDatabase db;
- const QStringList families = db.families();
+ const QStringList families = QFontDatabase::families();
const char **tf = tryFonts;
while (tf && *tf) {
// QTBUG-31689, family might be an English alias for a localized font name.
const QString family = QString::fromLatin1(*tf);
- if (families.contains(family) || db.hasFamily(family))
+ if (families.contains(family) || QFontDatabase::hasFamily(family))
result << family;
++tf;
}
@@ -965,4 +991,23 @@ QStringList QWindowsFontDatabaseBase::extraTryFontsForFamily(const QString &fami
return result;
}
+QFontDef QWindowsFontDatabaseBase::sanitizeRequest(QFontDef request) const
+{
+ QFontDef req = request;
+ const QString fam = request.families.front();
+ if (fam.isEmpty())
+ req.families[0] = QStringLiteral("MS Sans Serif");
+
+ if (fam == "MS Sans Serif"_L1) {
+ int height = -qRound(request.pixelSize);
+ // MS Sans Serif has bearing problems in italic, and does not scale
+ if (request.style == QFont::StyleItalic || (height > 18 && height != 24))
+ req.families[0] = QStringLiteral("Arial");
+ }
+
+ if (!(request.styleStrategy & QFont::StyleStrategy::PreferBitmap) && fam == u"Courier")
+ req.families[0] = QStringLiteral("Courier New");
+ return req;
+}
+
QT_END_NAMESPACE