summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.bat2
-rw-r--r--examples/widgets/animation/easing/window.cpp2
-rw-r--r--examples/widgets/widgets/icons/mainwindow.cpp11
-rw-r--r--examples/widgets/widgets/icons/mainwindow.h3
-rw-r--r--qmake/library/proitems.h3
-rw-r--r--src/corelib/kernel/qvariant.cpp2
-rw-r--r--src/corelib/kernel/qvariant.h2
-rw-r--r--src/corelib/serialization/qdatastream.h56
-rw-r--r--src/corelib/tools/qversionnumber.h54
-rw-r--r--src/dbus/qdbusargument.cpp7
-rw-r--r--src/dbus/qdbusargument.h106
-rw-r--r--src/gui/configure.json20
-rw-r--r--src/gui/kernel/qguiapplication.cpp7
-rw-r--r--src/gui/kernel/qplatformgraphicsbufferhelper.h2
-rw-r--r--src/gui/opengl/opengl.pri2
-rw-r--r--src/gui/painting/qpainter.cpp151
-rw-r--r--src/gui/painting/qpainter_p.h2
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp439
-rw-r--r--src/gui/painting/qplatformbackingstore.h16
-rw-r--r--src/opengl/opengl.pro2
-rw-r--r--src/opengl/qopengltextureblitter.cpp (renamed from src/gui/opengl/qopengltextureblitter.cpp)4
-rw-r--r--src/opengl/qopengltextureblitter.h (renamed from src/gui/opengl/qopengltextureblitter.h)10
-rw-r--r--src/opengl/qopenglwindow.cpp2
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp465
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h96
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp784
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h37
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp861
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h131
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp51
-rw-r--r--src/platformsupport/fontdatabases/windows/windows.pri10
-rw-r--r--src/platformsupport/platformcompositor/platformcompositor.pro4
-rw-r--r--src/platformsupport/platformcompositor/qopenglcompositor_p.h2
-rw-r--r--src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp455
-rw-r--r--src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.h87
-rw-r--r--src/plugins/platforms/android/android.pro2
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp10
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm14
-rw-r--r--src/plugins/platforms/ios/kernel.pro2
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm10
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp1
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h3
-rw-r--r--src/plugins/platforms/wasm/qwasmintegration.cpp2
-rw-r--r--src/plugins/platforms/wasm/wasm.pro2
-rw-r--r--src/plugins/platforms/windows/qwindowsgdiintegration.cpp10
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp18
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.h3
-rw-r--r--src/plugins/platforms/windows/windows.pro2
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp9
-rw-r--r--src/plugins/platforms/winrt/winrt.pro2
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp24
-rw-r--r--src/plugins/platforms/xcb/xcb_qpa_lib.pro3
-rw-r--r--src/tools/moc/generator.cpp2
-rw-r--r--src/tools/rcc/rcc.cpp20
-rw-r--r--src/widgets/widgets/qabstractbutton.cpp48
-rw-r--r--src/widgets/widgets/qbuttongroup.cpp43
-rw-r--r--src/widgets/widgets/qbuttongroup.h10
-rw-r--r--src/widgets/widgets/qwidgettextcontrol.cpp2
-rw-r--r--src/xml/dom/qdom.cpp12
-rw-r--r--tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp67
-rw-r--r--tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp30
-rw-r--r--tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp48
-rw-r--r--tests/auto/gui/qopengl/tst_qopengl.cpp2
-rw-r--r--tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp16
-rw-r--r--tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp12
-rw-r--r--tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp37
67 files changed, 2715 insertions, 1641 deletions
diff --git a/configure.bat b/configure.bat
index b34e146f5f..163e296874 100644
--- a/configure.bat
+++ b/configure.bat
@@ -261,7 +261,7 @@ if "%tmpl%" == "win32" (
echo QMAKESPEC = %PLATFORM%>> Makefile
) else (
echo QMAKESPEC = $^(SOURCE_PATH^)/mkspecs/%PLATFORM%>> Makefile
- echo CONFIG_CXXFLAGS = -std=c++11 -ffunction-sections>> Makefile
+ echo CONFIG_CXXFLAGS = -std=c++17 -ffunction-sections>> Makefile
echo CONFIG_LFLAGS = -Wl,--gc-sections>> Makefile
type "%QTSRC%\qmake\Makefile.unix.win32" >> Makefile
type "%QTSRC%\qmake\Makefile.unix.mingw" >> Makefile
diff --git a/examples/widgets/animation/easing/window.cpp b/examples/widgets/animation/easing/window.cpp
index 378af07535..51d252e52b 100644
--- a/examples/widgets/animation/easing/window.cpp
+++ b/examples/widgets/animation/easing/window.cpp
@@ -67,7 +67,7 @@ Window::Window(QWidget *parent)
connect(m_ui.easingCurvePicker, &QListWidget::currentRowChanged,
this, &Window::curveChanged);
- connect(m_ui.buttonGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked),
+ connect(m_ui.buttonGroup, &QButtonGroup::buttonClicked,
this, &Window::pathChanged);
connect(m_ui.periodSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
this, &Window::periodChanged);
diff --git a/examples/widgets/widgets/icons/mainwindow.cpp b/examples/widgets/widgets/icons/mainwindow.cpp
index 4f990f7320..928470b054 100644
--- a/examples/widgets/widgets/icons/mainwindow.cpp
+++ b/examples/widgets/widgets/icons/mainwindow.cpp
@@ -172,15 +172,16 @@ void MainWindow::changeStyle(bool checked)
//! [4]
//! [5]
-void MainWindow::changeSize(int id, bool checked)
+void MainWindow::changeSize(QAbstractButton *button, bool checked)
{
if (!checked)
return;
- const bool other = id == int(OtherSize);
+ const int index = sizeButtonGroup->id(button);
+ const bool other = index == int(OtherSize);
const int extent = other
? otherSpinBox->value()
- : QApplication::style()->pixelMetric(static_cast<QStyle::PixelMetric>(id));
+ : QApplication::style()->pixelMetric(static_cast<QStyle::PixelMetric>(index));
previewArea->setSize(QSize(extent, extent));
otherSpinBox->setEnabled(other);
@@ -188,7 +189,7 @@ void MainWindow::changeSize(int id, bool checked)
void MainWindow::triggerChangeSize()
{
- changeSize(sizeButtonGroup->checkedId(), true);
+ changeSize(sizeButtonGroup->checkedButton(), true);
}
//! [5]
@@ -372,7 +373,7 @@ QWidget *MainWindow::createIconSizeGroupBox()
sizeButtonGroup = new QButtonGroup(this);
sizeButtonGroup->setExclusive(true);
- connect(sizeButtonGroup, QOverload<int, bool>::of(&QButtonGroup::buttonToggled),
+ connect(sizeButtonGroup, &QButtonGroup::buttonToggled,
this, &MainWindow::changeSize);
QRadioButton *smallRadioButton = new QRadioButton;
diff --git a/examples/widgets/widgets/icons/mainwindow.h b/examples/widgets/widgets/icons/mainwindow.h
index c67d828cab..9250711ecc 100644
--- a/examples/widgets/widgets/icons/mainwindow.h
+++ b/examples/widgets/widgets/icons/mainwindow.h
@@ -62,6 +62,7 @@ class QActionGroup;
class QLabel;
class QButtonGroup;
class QTableWidget;
+class QAbstractButton;
QT_END_NAMESPACE
class IconPreviewArea;
class IconSizeSpinBox;
@@ -81,7 +82,7 @@ public:
private slots:
void about();
void changeStyle(bool checked);
- void changeSize(int, bool);
+ void changeSize(QAbstractButton *button, bool);
void triggerChangeSize();
void changeIcon();
void addSampleImages();
diff --git a/qmake/library/proitems.h b/qmake/library/proitems.h
index 4569d7c3ff..01370959c7 100644
--- a/qmake/library/proitems.h
+++ b/qmake/library/proitems.h
@@ -35,6 +35,7 @@
#include <qstring.h>
#include <qvector.h>
#include <qhash.h>
+#include <qmap.h>
QT_BEGIN_NAMESPACE
@@ -316,7 +317,7 @@ Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE);
inline ProStringList operator+(const ProStringList &one, const ProStringList &two)
{ ProStringList ret = one; ret += two; return ret; }
-typedef QHash<ProKey, ProStringList> ProValueMap;
+typedef QMap<ProKey, ProStringList> ProValueMap;
// These token definitions affect both ProFileEvaluator and ProWriter
enum ProToken {
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 7e3c01d461..4ac26e3048 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -972,7 +972,7 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
const QVariantMap *map = v_cast<QVariantMap>(d);
const auto end = map->end();
for (auto it = map->begin(); it != end; ++it)
- static_cast<QMultiHash<QString, QVariant> *>(hash)->insert(it.key(), it.value());
+ hash->insert(it.key(), it.value());
#ifndef QT_BOOTSTRAPPED
} else if (d->type == QMetaType::QCborValue) {
if (!v_cast<QCborValue>(d)->isMap())
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 353bfa7ce7..a09a70548c 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -818,7 +818,7 @@ namespace QtPrivate {
QVariantHash l;
l.reserve(iter.size());
for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it)
- static_cast<QMultiHash<QString, QVariant> &>(l).insert(it.key().toString(), it.value());
+ l.insert(it.key().toString(), it.value());
return l;
}
return QVariantValueHelper<QVariantHash>::invoke(v);
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index b7c16018d5..270267e29e 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -296,10 +296,7 @@ QDataStream &readAssociativeContainer(QDataStream &s, Container &c)
c.clear();
break;
}
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- c.insertMulti(k, t);
-QT_WARNING_POP
+ c.insert(k, t);
}
return s;
@@ -319,19 +316,20 @@ template <typename Container>
QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
{
s << quint32(c.size());
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && QT_DEPRECATED_SINCE(5, 15)
- // Deserialization should occur in the reverse order.
- // Otherwise, value() will return the least recently inserted
- // value instead of the most recently inserted one.
- auto it = c.constEnd();
- auto begin = c.constBegin();
- while (it != begin) {
- QT_WARNING_PUSH
- QT_WARNING_DISABLE_DEPRECATED
- --it;
- QT_WARNING_POP
+ auto it = c.constBegin();
+ auto end = c.constEnd();
+ while (it != end) {
s << it.key() << it.value();
-#else
+ ++it;
+ }
+
+ return s;
+}
+
+template <typename Container>
+QDataStream &writeAssociativeMultiContainer(QDataStream &s, const Container &c)
+{
+ s << quint32(c.size());
auto it = c.constBegin();
auto end = c.constEnd();
while (it != end) {
@@ -343,7 +341,6 @@ QDataStream &writeAssociativeContainer(QDataStream &s, const Container &c)
auto next = std::next(rangeStart, i);
s << next.key() << next.value();
}
-#endif
}
return s;
@@ -440,12 +437,25 @@ inline QDataStream &operator>>(QDataStream &s, QHash<Key, T> &hash)
}
template <class Key, class T>
+
inline QDataStream &operator<<(QDataStream &s, const QHash<Key, T> &hash)
{
return QtPrivate::writeAssociativeContainer(s, hash);
}
template <class Key, class T>
+inline QDataStream &operator>>(QDataStream &s, QMultiHash<Key, T> &hash)
+{
+ return QtPrivate::readAssociativeContainer(s, hash);
+}
+
+template <class Key, class T>
+inline QDataStream &operator<<(QDataStream &s, const QMultiHash<Key, T> &hash)
+{
+ return QtPrivate::writeAssociativeMultiContainer(s, hash);
+}
+
+template <class Key, class T>
inline QDataStream &operator>>(QDataStream &s, QMap<Key, T> &map)
{
return QtPrivate::readAssociativeContainer(s, map);
@@ -457,6 +467,18 @@ inline QDataStream &operator<<(QDataStream &s, const QMap<Key, T> &map)
return QtPrivate::writeAssociativeContainer(s, map);
}
+template <class Key, class T>
+inline QDataStream &operator>>(QDataStream &s, QMultiMap<Key, T> &map)
+{
+ return QtPrivate::readAssociativeContainer(s, map);
+}
+
+template <class Key, class T>
+inline QDataStream &operator<<(QDataStream &s, const QMultiMap<Key, T> &map)
+{
+ return QtPrivate::writeAssociativeMultiContainer(s, map);
+}
+
#ifndef QT_NO_DATASTREAM
template <class T1, class T2>
inline QDataStream& operator>>(QDataStream& s, QPair<T1, T2>& p)
diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h
index 9fd4242859..03a27548b8 100644
--- a/src/corelib/tools/qversionnumber.h
+++ b/src/corelib/tools/qversionnumber.h
@@ -344,30 +344,30 @@ public:
if_valid_segment_type<Minor> = true>
static constexpr QTypeRevision fromVersion(Major majorVersion, Minor minorVersion)
{
- Q_ASSERT(isValidSegment(majorVersion));
- Q_ASSERT(isValidSegment(minorVersion));
- return QTypeRevision(quint8(majorVersion), quint8(minorVersion));
+ return Q_ASSERT(isValidSegment(majorVersion)),
+ Q_ASSERT(isValidSegment(minorVersion)),
+ QTypeRevision(quint8(majorVersion), quint8(minorVersion));
}
template<typename Major, if_valid_segment_type<Major> = true>
static constexpr QTypeRevision fromMajorVersion(Major majorVersion)
{
- Q_ASSERT(isValidSegment(majorVersion));
- return QTypeRevision(quint8(majorVersion), SegmentUnknown);
+ return Q_ASSERT(isValidSegment(majorVersion)),
+ QTypeRevision(quint8(majorVersion), SegmentUnknown);
}
template<typename Minor, if_valid_segment_type<Minor> = true>
static constexpr QTypeRevision fromMinorVersion(Minor minorVersion)
{
- Q_ASSERT(isValidSegment(minorVersion));
- return QTypeRevision(SegmentUnknown, quint8(minorVersion));
+ return Q_ASSERT(isValidSegment(minorVersion)),
+ QTypeRevision(SegmentUnknown, quint8(minorVersion));
}
template<typename Integer, if_valid_value_type<Integer> = true>
static constexpr QTypeRevision fromEncodedVersion(Integer value)
{
- Q_ASSERT((value & ~Integer(0xffff)) == Integer(0));
- return QTypeRevision((value & Integer(0xff00)) >> 8, value & Integer(0xff));
+ return Q_ASSERT((value & ~Integer(0xffff)) == Integer(0)),
+ QTypeRevision((value & Integer(0xff00)) >> 8, value & Integer(0xff));
}
static constexpr QTypeRevision zero() { return QTypeRevision(0, 0); }
@@ -416,6 +416,42 @@ inline constexpr bool operator!=(QTypeRevision lhs, QTypeRevision rhs)
return lhs.toEncodedVersion<quint16>() != rhs.toEncodedVersion<quint16>();
}
+inline constexpr bool operator<(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return (!lhs.hasMajorVersion() && rhs.hasMajorVersion())
+ // non-0 major > unspecified major > major 0
+ ? rhs.majorVersion() != 0
+ : ((lhs.hasMajorVersion() && !rhs.hasMajorVersion())
+ // major 0 < unspecified major < non-0 major
+ ? lhs.majorVersion() == 0
+ : (lhs.majorVersion() != rhs.majorVersion()
+ // both majors specified and non-0
+ ? lhs.majorVersion() < rhs.majorVersion()
+ : ((!lhs.hasMinorVersion() && rhs.hasMinorVersion())
+ // non-0 minor > unspecified minor > minor 0
+ ? rhs.minorVersion() != 0
+ : ((lhs.hasMinorVersion() && !rhs.hasMinorVersion())
+ // minor 0 < unspecified minor < non-0 minor
+ ? lhs.minorVersion() == 0
+ // both minors specified and non-0
+ : lhs.minorVersion() < rhs.minorVersion()))));
+}
+
+inline constexpr bool operator>(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs != rhs && !(lhs < rhs);
+}
+
+inline constexpr bool operator<=(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs == rhs || lhs < rhs;
+}
+
+inline constexpr bool operator>=(QTypeRevision lhs, QTypeRevision rhs)
+{
+ return lhs == rhs || !(lhs < rhs);
+}
+
Q_STATIC_ASSERT(sizeof(QTypeRevision) == 2);
Q_DECLARE_TYPEINFO(QTypeRevision, Q_MOVABLE_TYPE);
diff --git a/src/dbus/qdbusargument.cpp b/src/dbus/qdbusargument.cpp
index 5a0f0f013b..7e1d847982 100644
--- a/src/dbus/qdbusargument.cpp
+++ b/src/dbus/qdbusargument.cpp
@@ -908,9 +908,10 @@ void QDBusArgument::endArray()
\snippet code/src_qdbus_qdbusargument.cpp 7
- If the type you want to marshall is a QMap or QHash, you need not
- declare an \c{operator<<} function for it, since Qt D-Bus provides
- generic templates to do the job of marshalling the data.
+ You usually don't need to provide an \c{operator<<} or \c{operator>>}
+ function for associative containers such as QHash or std::map,
+ since Qt D-Bus provides generic templates to do the job of marshalling
+ the data.
\sa endMap(), beginStructure(), beginArray(), beginMapEntry()
*/
diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h
index 339f8c5dc8..f388a65bed 100644
--- a/src/dbus/qdbusargument.h
+++ b/src/dbus/qdbusargument.h
@@ -224,7 +224,8 @@ Q_DBUS_EXPORT const QDBusArgument &operator>>(const QDBusArgument &a, QLineF &li
Q_DBUS_EXPORT QDBusArgument &operator<<(QDBusArgument &a, const QLineF &line);
#endif
-template<template <typename> class Container, typename T>
+template<template <typename> class Container, typename T,
+ typename = typename Container<T>::iterator>
inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<T> &list)
{
int id = qMetaTypeId<T>();
@@ -237,7 +238,8 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<T> &list)
return arg;
}
-template<template <typename> class Container, typename T>
+template<template <typename> class Container, typename T,
+ typename = typename Container<T>::iterator>
inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<T> &list)
{
arg.beginArray();
@@ -252,35 +254,6 @@ inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<T> &l
return arg;
}
-// QList specializations
-template<typename T>
-inline QDBusArgument &operator<<(QDBusArgument &arg, const QList<T> &list)
-{
- int id = qMetaTypeId<T>();
- arg.beginArray(id);
- typename QList<T>::ConstIterator it = list.constBegin();
- typename QList<T>::ConstIterator end = list.constEnd();
- for ( ; it != end; ++it)
- arg << *it;
- arg.endArray();
- return arg;
-}
-
-template<typename T>
-inline const QDBusArgument &operator>>(const QDBusArgument &arg, QList<T> &list)
-{
- arg.beginArray();
- list.clear();
- while (!arg.atEnd()) {
- T item;
- arg >> item;
- list.push_back(item);
- }
- arg.endArray();
-
- return arg;
-}
-
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantList &list)
{
int id = qMetaTypeId<QDBusVariant>();
@@ -293,15 +266,16 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantList &list)
return arg;
}
-// QMap specializations
-template<typename Key, typename T>
-inline QDBusArgument &operator<<(QDBusArgument &arg, const QMap<Key, T> &map)
+// Specializations for associative containers
+template <template <typename, typename> class Container, typename Key, typename T,
+ QtPrivate::IfAssociativeIteratorHasKeyAndValue<typename Container<Key, T>::iterator> = true>
+inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<Key, T> &map)
{
int kid = qMetaTypeId<Key>();
int vid = qMetaTypeId<T>();
arg.beginMap(kid, vid);
- typename QMap<Key, T>::ConstIterator it = map.constBegin();
- typename QMap<Key, T>::ConstIterator end = map.constEnd();
+ auto it = map.begin();
+ auto end = map.end();
for ( ; it != end; ++it) {
arg.beginMapEntry();
arg << it.key() << it.value();
@@ -311,8 +285,27 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const QMap<Key, T> &map)
return arg;
}
-template<typename Key, typename T>
-inline const QDBusArgument &operator>>(const QDBusArgument &arg, QMap<Key, T> &map)
+template <template <typename, typename> class Container, typename Key, typename T,
+ QtPrivate::IfAssociativeIteratorHasFirstAndSecond<typename Container<Key, T>::iterator> = true>
+inline QDBusArgument &operator<<(QDBusArgument &arg, const Container<Key, T> &map)
+{
+ int kid = qMetaTypeId<Key>();
+ int vid = qMetaTypeId<T>();
+ arg.beginMap(kid, vid);
+ auto it = map.begin();
+ auto end = map.end();
+ for ( ; it != end; ++it) {
+ arg.beginMapEntry();
+ arg << it->first << it->second;
+ arg.endMapEntry();
+ }
+ arg.endMap();
+ return arg;
+}
+
+template <template <typename, typename> class Container, typename Key, typename T,
+ typename = typename Container<Key, T>::iterator>
+inline const QDBusArgument &operator>>(const QDBusArgument &arg, Container<Key, T> &map)
{
arg.beginMap();
map.clear();
@@ -321,7 +314,7 @@ inline const QDBusArgument &operator>>(const QDBusArgument &arg, QMap<Key, T> &m
T value;
arg.beginMapEntry();
arg >> key >> value;
- static_cast<QMultiMap<Key, T> &>(map).insert(key, value);
+ map.insert(key, value);
arg.endMapEntry();
}
arg.endMap();
@@ -342,41 +335,6 @@ inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantMap &map)
return arg;
}
-// QHash specializations
-template<typename Key, typename T>
-inline QDBusArgument &operator<<(QDBusArgument &arg, const QHash<Key, T> &map)
-{
- int kid = qMetaTypeId<Key>();
- int vid = qMetaTypeId<T>();
- arg.beginMap(kid, vid);
- typename QHash<Key, T>::ConstIterator it = map.constBegin();
- typename QHash<Key, T>::ConstIterator end = map.constEnd();
- for ( ; it != end; ++it) {
- arg.beginMapEntry();
- arg << it.key() << it.value();
- arg.endMapEntry();
- }
- arg.endMap();
- return arg;
-}
-
-template<typename Key, typename T>
-inline const QDBusArgument &operator>>(const QDBusArgument &arg, QHash<Key, T> &map)
-{
- arg.beginMap();
- map.clear();
- while (!arg.atEnd()) {
- Key key;
- T value;
- arg.beginMapEntry();
- arg >> key >> value;
- static_cast<QMultiHash<Key, T> &>(map).insert(key, value);
- arg.endMapEntry();
- }
- arg.endMap();
- return arg;
-}
-
inline QDBusArgument &operator<<(QDBusArgument &arg, const QVariantHash &map)
{
arg.beginMap(QMetaType::QString, qMetaTypeId<QDBusVariant>());
diff --git a/src/gui/configure.json b/src/gui/configure.json
index 469473af22..8bc3e8dc0c 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -189,6 +189,20 @@
"-ldwrite"
]
},
+ "dwrite_3": {
+ "label": "DirectWrite 3",
+ "test": {
+ "main": [
+ "IUnknown *factory = 0;",
+ "DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory3),",
+ " &factory);"
+ ]
+ },
+ "headers": "dwrite_3.h",
+ "sources": [
+ "-ldwrite"
+ ]
+ },
"drm": {
"label": "KMS",
"test": {
@@ -1145,6 +1159,12 @@
"condition": "libs.dwrite_1",
"output": [ "privateFeature" ]
},
+ "directwrite3": {
+ "label": "DirectWrite 3",
+ "emitIf": "config.win32",
+ "condition": "features.directwrite1 && libs.dwrite_3",
+ "output": [ "privateFeature" ]
+ },
"directwrite2": {
"label": "DirectWrite 2",
"emitIf": "config.win32",
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index a723ca6e7f..1f8d8d21e9 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -613,6 +613,13 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\li \c {dpiawareness=[0|1|2} Sets the DPI awareness of the process
(see \l{High DPI Displays}, since Qt 5.4).
\li \c {fontengine=freetype}, uses the FreeType font engine.
+ \li \c {fontengine=directwrite}, uses the experimental DirectWrite
+ font database and defaults to using the DirectWrite font
+ engine (which is otherwise only used for some font types
+ or font properties.) This affects font selection and aims
+ to provide font naming more consistent with other platforms,
+ but does not support all font formats, such as Postscript
+ Type-1 or Microsoft FNT fonts.
\li \c {menus=[native|none]}, controls the use of native menus.
Native menus are implemented using Win32 API and are simpler than
diff --git a/src/gui/kernel/qplatformgraphicsbufferhelper.h b/src/gui/kernel/qplatformgraphicsbufferhelper.h
index bfe61713d4..36afd4877b 100644
--- a/src/gui/kernel/qplatformgraphicsbufferhelper.h
+++ b/src/gui/kernel/qplatformgraphicsbufferhelper.h
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
namespace QPlatformGraphicsBufferHelper {
- bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, bool *premultipliedB, const QRect &rect = QRect());
+ Q_GUI_EXPORT bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, bool *premultipliedB, const QRect &rect = QRect());
bool bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB = nullptr, bool *premultipliedB = nullptr, const QRect &rect = QRect());
}
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri
index f1e2019417..8d91a9e4b2 100644
--- a/src/gui/opengl/opengl.pri
+++ b/src/gui/opengl/opengl.pri
@@ -16,7 +16,6 @@ qtConfig(opengl) {
opengl/qopenglversionfunctions.h \
opengl/qopenglversionfunctionsfactory_p.h \
opengl/qopenglvertexarrayobject.h \
- opengl/qopengltextureblitter.h \
opengl/qopenglextrafunctions.h \
opengl/qopenglprogrambinarycache_p.h
@@ -28,7 +27,6 @@ qtConfig(opengl) {
opengl/qopenglversionfunctions.cpp \
opengl/qopenglversionfunctionsfactory.cpp \
opengl/qopenglvertexarrayobject.cpp \
- opengl/qopengltextureblitter.cpp \
opengl/qopenglprogrambinarycache.cpp
!qtConfig(opengles2) {
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 390147463d..8aedf2c34d 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -96,10 +96,15 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
QTextItem::RenderFlags flags, qreal width,
const QTextCharFormat &charFormat);
// Helper function to calculate left most position, width and flags for decoration drawing
-Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
- const QFixedPoint *positions, int glyphCount,
- QFontEngine *fontEngine, const QFont &font,
- const QTextCharFormat &charFormat);
+static void qt_draw_decoration_for_glyphs(QPainter *painter,
+ const QPointF &decorationPosition,
+ const glyph_t *glyphArray,
+ const QFixedPoint *positions,
+ int glyphCount,
+ QFontEngine *fontEngine,
+ bool underline,
+ bool overline,
+ bool strikeOut);
static inline QGradient::CoordinateMode coordinateMode(const QBrush &brush)
{
@@ -5607,40 +5612,31 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun)
fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
}
- d->drawGlyphs(glyphIndexes, fixedPointPositions.data(), count, fontD->fontEngine,
- glyphRun.overline(), glyphRun.underline(), glyphRun.strikeOut());
+ d->drawGlyphs(engineRequiresPretransformedGlyphPositions
+ ? d->state->transform().map(position)
+ : position,
+ glyphIndexes,
+ fixedPointPositions.data(),
+ count,
+ fontD->fontEngine,
+ glyphRun.overline(),
+ glyphRun.underline(),
+ glyphRun.strikeOut());
}
-void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positions,
+void QPainterPrivate::drawGlyphs(const QPointF &decorationPosition,
+ const quint32 *glyphArray,
+ QFixedPoint *positions,
int glyphCount,
- QFontEngine *fontEngine, bool overline, bool underline,
+ QFontEngine *fontEngine,
+ bool overline,
+ bool underline,
bool strikeOut)
{
Q_Q(QPainter);
updateState(state);
- QFixed leftMost;
- QFixed rightMost;
- QFixed baseLine;
- for (int i=0; i<glyphCount; ++i) {
- glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
- if (i == 0 || leftMost > positions[i].x)
- leftMost = positions[i].x;
-
- // We don't support glyphs that do not share a common baseline. If this turns out to
- // be a relevant use case, then we need to find clusters of glyphs that share a baseline
- // and do a drawTextItemDecorations call per cluster.
- if (i == 0 || baseLine < positions[i].y)
- baseLine = positions[i].y;
-
- // We use the advance rather than the actual bounds to match the algorithm in drawText()
- if (i == 0 || rightMost < positions[i].x + gm.xoff)
- rightMost = positions[i].x + gm.xoff;
- }
-
- QFixed width = rightMost - leftMost;
-
if (extended != nullptr && state->matrix.isAffine()) {
QStaticTextItem staticTextItem;
staticTextItem.color = state->pen.color();
@@ -5674,21 +5670,15 @@ void QPainterPrivate::drawGlyphs(const quint32 *glyphArray, QFixedPoint *positio
engine->drawTextItem(QPointF(0, 0), textItem);
}
- QTextItemInt::RenderFlags flags;
- if (underline)
- flags |= QTextItemInt::Underline;
- if (overline)
- flags |= QTextItemInt::Overline;
- if (strikeOut)
- flags |= QTextItemInt::StrikeOut;
-
- drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()),
- fontEngine,
- nullptr, // textEngine
- (underline
- ? QTextCharFormat::SingleUnderline
- : QTextCharFormat::NoUnderline),
- flags, width.toReal(), QTextCharFormat());
+ qt_draw_decoration_for_glyphs(q,
+ decorationPosition,
+ glyphArray,
+ positions,
+ glyphCount,
+ fontEngine,
+ underline,
+ overline,
+ strikeOut);
}
#endif // QT_NO_RAWFONT
@@ -5868,9 +5858,15 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText
}
d->extended->drawStaticTextItem(item);
- qt_draw_decoration_for_glyphs(this, item->glyphs, item->glyphPositions,
- item->numGlyphs, item->fontEngine(), staticText_d->font,
- QTextCharFormat());
+ qt_draw_decoration_for_glyphs(this,
+ topLeftPosition,
+ item->glyphs,
+ item->glyphPositions,
+ item->numGlyphs,
+ item->fontEngine(),
+ staticText_d->font.underline(),
+ staticText_d->font.overline(),
+ staticText_d->font.strikeOut());
}
if (currentColor != oldPen.color())
setPen(oldPen);
@@ -6375,49 +6371,44 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
painter->setRenderHint(QPainter::Qt4CompatiblePainting);
}
-Q_GUI_EXPORT void qt_draw_decoration_for_glyphs(QPainter *painter, const glyph_t *glyphArray,
- const QFixedPoint *positions, int glyphCount,
- QFontEngine *fontEngine, const QFont &font,
- const QTextCharFormat &charFormat)
+static void qt_draw_decoration_for_glyphs(QPainter *painter,
+ const QPointF &decorationPosition,
+ const glyph_t *glyphArray,
+ const QFixedPoint *positions,
+ int glyphCount,
+ QFontEngine *fontEngine,
+ bool underline,
+ bool overline,
+ bool strikeOut)
{
- if (!(font.underline() || font.strikeOut() || font.overline()))
+ if (!underline && !overline && !strikeOut)
return;
- QFixed leftMost;
- QFixed rightMost;
- QFixed baseLine;
- for (int i=0; i<glyphCount; ++i) {
- glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[i]);
- if (i == 0 || leftMost > positions[i].x)
- leftMost = positions[i].x;
-
- // We don't support glyphs that do not share a common baseline. If this turns out to
- // be a relevant use case, then we need to find clusters of glyphs that share a baseline
- // and do a drawTextItemDecoration call per cluster.
- if (i == 0 || baseLine < positions[i].y)
- baseLine = positions[i].y;
-
- // We use the advance rather than the actual bounds to match the algorithm in drawText()
- if (i == 0 || rightMost < positions[i].x + gm.xoff)
- rightMost = positions[i].x + gm.xoff;
- }
-
- QFixed width = rightMost - leftMost;
QTextItem::RenderFlags flags;
-
- if (font.underline())
+ if (underline)
flags |= QTextItem::Underline;
- if (font.overline())
+ if (overline)
flags |= QTextItem::Overline;
- if (font.strikeOut())
+ if (strikeOut)
flags |= QTextItem::StrikeOut;
- drawTextItemDecoration(painter, QPointF(leftMost.toReal(), baseLine.toReal()),
+ bool rtl = positions[glyphCount - 1].x < positions[0].x;
+ QFixed baseline = positions[0].y;
+ glyph_metrics_t gm = fontEngine->boundingBox(glyphArray[rtl ? 0 : glyphCount - 1]);
+
+ qreal width = rtl
+ ? (positions[0].x + gm.xoff - positions[glyphCount - 1].x).toReal()
+ : (positions[glyphCount - 1].x + gm.xoff - positions[0].x).toReal();
+
+ drawTextItemDecoration(painter,
+ QPointF(decorationPosition.x(), baseline.toReal()),
fontEngine,
nullptr, // textEngine
- font.underline() ? QTextCharFormat::SingleUnderline
- : QTextCharFormat::NoUnderline, flags,
- width.toReal(), charFormat);
+ underline ? QTextCharFormat::SingleUnderline
+ : QTextCharFormat::NoUnderline,
+ flags,
+ width,
+ QTextCharFormat());
}
void QPainter::drawTextItem(const QPointF &p, const QTextItem &ti)
diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h
index dafd6e33be..870381d48a 100644
--- a/src/gui/painting/qpainter_p.h
+++ b/src/gui/painting/qpainter_p.h
@@ -235,7 +235,7 @@ public:
void drawTextItem(const QPointF &p, const QTextItem &_ti, QTextEngine *textEngine);
#if !defined(QT_NO_RAWFONT)
- void drawGlyphs(const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount,
+ void drawGlyphs(const QPointF &decorationPosition, const quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount,
QFontEngine *fontEngine, bool overline = false, bool underline = false,
bool strikeOut = false);
#endif
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index c092a7153f..e8ac494e04 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -40,43 +40,8 @@
#include "qplatformbackingstore.h"
#include <qwindow.h>
#include <qpixmap.h>
-#include <private/qwindow_p.h>
-
-#include <qopengl.h>
-#include <qopenglcontext.h>
-#include <QtGui/QMatrix4x4>
-#include <QtGui/QOpenGLShaderProgram>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QOpenGLFunctions>
-#ifndef QT_NO_OPENGL
-#include <QtGui/qopengltextureblitter.h>
-#include <QtGui/qoffscreensurface.h>
-#endif
-#include <qpa/qplatformgraphicsbuffer.h>
-#include <qpa/qplatformgraphicsbufferhelper.h>
-#ifndef GL_TEXTURE_BASE_LEVEL
-#define GL_TEXTURE_BASE_LEVEL 0x813C
-#endif
-#ifndef GL_TEXTURE_MAX_LEVEL
-#define GL_TEXTURE_MAX_LEVEL 0x813D
-#endif
-#ifndef GL_UNPACK_ROW_LENGTH
-#define GL_UNPACK_ROW_LENGTH 0x0CF2
-#endif
-#ifndef GL_RGB10_A2
-#define GL_RGB10_A2 0x8059
-#endif
-#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
-#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
-#endif
-
-#ifndef GL_FRAMEBUFFER_SRGB
-#define GL_FRAMEBUFFER_SRGB 0x8DB9
-#endif
-#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE
-#define GL_FRAMEBUFFER_SRGB_CAPABLE 0x8DBA
-#endif
+#include <QtCore/private/qobject_p.h>
QT_BEGIN_NAMESPACE
@@ -88,38 +53,19 @@ public:
QPlatformBackingStorePrivate(QWindow *w)
: window(w)
, backingStore(nullptr)
-#ifndef QT_NO_OPENGL
- , textureId(0)
- , blitter(nullptr)
-#endif
{
}
~QPlatformBackingStorePrivate()
{
#ifndef QT_NO_OPENGL
- if (context) {
- QOffscreenSurface offscreenSurface;
- offscreenSurface.setFormat(context->format());
- offscreenSurface.create();
- context->makeCurrent(&offscreenSurface);
- if (textureId)
- context->functions()->glDeleteTextures(1, &textureId);
- if (blitter)
- blitter->destroy();
- }
- delete blitter;
+ delete openGLSupport;
#endif
}
QWindow *window;
QBackingStore *backingStore;
#ifndef QT_NO_OPENGL
- QScopedPointer<QOpenGLContext> context;
- mutable GLuint textureId;
- mutable QSize textureSize;
- mutable bool needsSwizzle;
- mutable bool premultiplied;
- QOpenGLTextureBlitter *blitter;
+ QPlatformBackingStoreOpenGLSupportBase *openGLSupport = nullptr;
#endif
};
@@ -240,83 +186,20 @@ void QPlatformTextureList::clear()
*/
#ifndef QT_NO_OPENGL
-
-static inline QRect deviceRect(const QRect &rect, QWindow *window)
-{
- QRect deviceRect(rect.topLeft() * window->devicePixelRatio(),
- rect.size() * window->devicePixelRatio());
- return deviceRect;
-}
-
-static inline QPoint deviceOffset(const QPoint &pt, QWindow *window)
-{
- return pt * window->devicePixelRatio();
-}
-
-static QRegion deviceRegion(const QRegion &region, QWindow *window, const QPoint &offset)
-{
- if (offset.isNull() && window->devicePixelRatio() <= 1)
- return region;
-
- QVector<QRect> rects;
- rects.reserve(region.rectCount());
- for (const QRect &rect : region)
- rects.append(deviceRect(rect.translated(offset), window));
-
- QRegion deviceRegion;
- deviceRegion.setRects(rects.constData(), rects.count());
- return deviceRegion;
-}
-
-static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
-{
- return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
- topLeftRect.width(), topLeftRect.height());
-}
-
-static void blitTextureForWidget(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect,
- QOpenGLTextureBlitter *blitter, const QPoint &offset, bool canUseSrgb)
-{
- const QRect clipRect = textures->clipRect(idx);
- if (clipRect.isEmpty())
- return;
-
- QRect rectInWindow = textures->geometry(idx);
- // relative to the TLW, not necessarily our window (if the flush is for a native child widget), have to adjust
- rectInWindow.translate(-offset);
-
- const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
- const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
-
- const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(deviceRect(clippedRectInWindow, window),
- deviceWindowRect);
-
- const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window),
- deviceRect(rectInWindow, window).size(),
- QOpenGLTextureBlitter::OriginBottomLeft);
-
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- const bool srgb = textures->flags(idx).testFlag(QPlatformTextureList::TextureIsSrgb);
- if (srgb && canUseSrgb)
- funcs->glEnable(GL_FRAMEBUFFER_SRGB);
-
- blitter->blit(textures->textureId(idx), target, source);
-
- if (srgb && canUseSrgb)
- funcs->glDisable(GL_FRAMEBUFFER_SRGB);
-}
-
/*!
Flushes the given \a region from the specified \a window onto the
screen, and composes it with the specified \a textures.
- The default implementation retrieves the contents using toTexture()
+ If OpenGLSupport has been enabled using \c setOpenGLSupport,
+ the default implementation retrieves the contents using toTexture()
and composes using OpenGL. May be reimplemented in subclasses if there
is a more efficient native way to do it.
\note \a region is relative to the window which may not be top-level in case
\a window corresponds to a native child widget. \a offset is the position of
the native child relative to the top-level window.
+
+ \sa setOpenGLSupport()
*/
void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &region,
@@ -324,162 +207,13 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
QPlatformTextureList *textures,
bool translucentBackground)
{
- if (!qt_window_private(window)->receivedExpose)
- return;
-
- if (!d_ptr->context) {
- d_ptr->context.reset(new QOpenGLContext);
- d_ptr->context->setFormat(d_ptr->window->requestedFormat());
- d_ptr->context->setScreen(d_ptr->window->screen());
- d_ptr->context->setShareContext(qt_window_private(d_ptr->window)->shareContext());
- if (!d_ptr->context->create()) {
- qCWarning(lcQpaBackingStore, "composeAndFlush: QOpenGLContext creation failed");
- return;
- }
- }
-
- bool current = d_ptr->context->makeCurrent(window);
-
- if (!current && !d_ptr->context->isValid()) {
- delete d_ptr->blitter;
- d_ptr->blitter = nullptr;
- d_ptr->textureId = 0;
- current = d_ptr->context->create() && d_ptr->context->makeCurrent(window);
- }
-
- if (!current) {
- qCWarning(lcQpaBackingStore, "composeAndFlush: makeCurrent() failed");
- return;
- }
-
- qCDebug(lcQpaBackingStore) << "Composing and flushing" << region << "of" << window
- << "at offset" << offset << "with" << textures->count() << "texture(s) in" << textures;
-
- QWindowPrivate::get(window)->lastComposeTime.start();
-
- QOpenGLFunctions *funcs = d_ptr->context->functions();
- funcs->glViewport(0, 0, qRound(window->width() * window->devicePixelRatio()), qRound(window->height() * window->devicePixelRatio()));
- funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
- funcs->glClear(GL_COLOR_BUFFER_BIT);
-
- if (!d_ptr->blitter) {
- d_ptr->blitter = new QOpenGLTextureBlitter;
- d_ptr->blitter->create();
- }
-
- d_ptr->blitter->bind();
-
- const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window);
- const QPoint deviceWindowOffset = deviceOffset(offset, window);
-
- bool canUseSrgb = false;
- // If there are any sRGB textures in the list, check if the destination
- // framebuffer is sRGB capable.
- for (int i = 0; i < textures->count(); ++i) {
- if (textures->flags(i).testFlag(QPlatformTextureList::TextureIsSrgb)) {
- GLint cap = 0;
- funcs->glGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE, &cap);
- if (cap)
- canUseSrgb = true;
- break;
- }
- }
-
- // Textures for renderToTexture widgets.
- for (int i = 0; i < textures->count(); ++i) {
- if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
- blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
- }
-
- // Backingstore texture with the normal widgets.
- GLuint textureId = 0;
- QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft;
- if (QPlatformGraphicsBuffer *graphicsBuffer = this->graphicsBuffer()) {
- if (graphicsBuffer->size() != d_ptr->textureSize) {
- if (d_ptr->textureId)
- funcs->glDeleteTextures(1, &d_ptr->textureId);
- funcs->glGenTextures(1, &d_ptr->textureId);
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
- }
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle, &d_ptr->premultiplied)) {
- d_ptr->textureSize = graphicsBuffer->size();
- } else {
- d_ptr->textureSize = QSize(0,0);
- }
-
- graphicsBuffer->unlock();
- } else if (!region.isEmpty()){
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle, &d_ptr->premultiplied);
- graphicsBuffer->unlock();
- }
-
- if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
- origin = QOpenGLTextureBlitter::OriginBottomLeft;
- textureId = d_ptr->textureId;
- } else {
- TextureFlags flags;
- textureId = toTexture(deviceRegion(region, window, offset), &d_ptr->textureSize, &flags);
- d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0;
- d_ptr->premultiplied = (flags & TexturePremultiplied) != 0;
- if (flags & TextureFlip)
- origin = QOpenGLTextureBlitter::OriginBottomLeft;
- }
-
- funcs->glEnable(GL_BLEND);
- if (d_ptr->premultiplied)
- funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ if (auto *c = d_ptr->openGLSupport)
+ c->composeAndFlush(window, region, offset, textures, translucentBackground);
else
- funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
-
- if (textureId) {
- if (d_ptr->needsSwizzle)
- d_ptr->blitter->setRedBlueSwizzle(true);
- // The backingstore is for the entire tlw.
- // In case of native children offset tells the position relative to the tlw.
- const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(deviceWindowOffset), d_ptr->textureSize.height());
- const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect,
- d_ptr->textureSize,
- origin);
- d_ptr->blitter->blit(textureId, QMatrix4x4(), source);
- if (d_ptr->needsSwizzle)
- d_ptr->blitter->setRedBlueSwizzle(false);
- }
-
- // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
- bool blendIsPremultiplied = d_ptr->premultiplied;
- for (int i = 0; i < textures->count(); ++i) {
- const QPlatformTextureList::Flags flags = textures->flags(i);
- if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending)) {
- if (!blendIsPremultiplied) {
- funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
- blendIsPremultiplied = true;
- }
- } else {
- if (blendIsPremultiplied) {
- funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
- blendIsPremultiplied = false;
- }
- }
- if (flags.testFlag(QPlatformTextureList::StacksOnTop))
- blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
- }
-
- funcs->glDisable(GL_BLEND);
- d_ptr->blitter->release();
-
- d_ptr->context->swapBuffers(window);
+ qWarning() << Q_FUNC_INFO << "no opengl support set";
}
#endif
+
/*!
Implemented in subclasses to return the content of the backingstore as a QImage.
@@ -504,7 +238,8 @@ QImage QPlatformBackingStore::toImage() const
The ownership of the texture is not transferred. The caller must not store
the return value between calls, but instead call this function before each use.
- The default implementation returns a cached texture if \a dirtyRegion is empty and
+ If OpenGLSupport has been enabled using \c setOpenGLSupport,
+ the default implementation returns a cached texture if \a dirtyRegion is empty and
\a textureSize matches the backingstore size, otherwise it retrieves the content using
toImage() and performs a texture upload. This works only if the value of \a textureSize
is preserved between the calls to this function.
@@ -520,141 +255,17 @@ QImage QPlatformBackingStore::toImage() const
flags will be set to include \c TextureFlip.
\note \a dirtyRegion is relative to the backingstore so no adjustment is needed.
+
+ \sa setOpenGLSupport()
*/
GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const
{
- Q_ASSERT(textureSize);
- Q_ASSERT(flags);
-
- QImage image = toImage();
- QSize imageSize = image.size();
-
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- GLenum internalFormat = GL_RGBA;
- GLuint pixelType = GL_UNSIGNED_BYTE;
-
- bool needsConversion = false;
- *flags = { };
- switch (image.format()) {
- case QImage::Format_ARGB32_Premultiplied:
- *flags |= TexturePremultiplied;
- Q_FALLTHROUGH();
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32:
- *flags |= TextureSwizzle;
- break;
- case QImage::Format_RGBA8888_Premultiplied:
- *flags |= TexturePremultiplied;
- Q_FALLTHROUGH();
- case QImage::Format_RGBX8888:
- case QImage::Format_RGBA8888:
- break;
- case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- internalFormat = GL_RGB10_A2;
- *flags |= TexturePremultiplied;
- } else {
- needsConversion = true;
- }
- break;
- case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- internalFormat = GL_RGB10_A2;
- *flags |= TextureSwizzle | TexturePremultiplied;
- } else {
- needsConversion = true;
- }
- break;
- default:
- needsConversion = true;
- break;
- }
- if (imageSize.isEmpty()) {
- *textureSize = imageSize;
+ if (auto *c = d_ptr->openGLSupport)
+ return c->toTexture(dirtyRegion, textureSize, flags);
+ else {
+ qWarning() << Q_FUNC_INFO << "no opengl support set";
return 0;
}
-
- // Must rely on the input only, not d_ptr.
- // With the default composeAndFlush() textureSize is &d_ptr->textureSize.
- bool resized = *textureSize != imageSize;
- if (dirtyRegion.isEmpty() && !resized)
- return d_ptr->textureId;
-
- *textureSize = imageSize;
-
- if (needsConversion)
- image = image.convertToFormat(QImage::Format_RGBA8888);
-
- // The image provided by the backingstore may have a stride larger than width * 4, for
- // instance on platforms that manually implement client-side decorations.
- static const int bytesPerPixel = 4;
- const int strideInPixels = image.bytesPerLine() / bytesPerPixel;
- const bool hasUnpackRowLength = !ctx->isOpenGLES() || ctx->format().majorVersion() >= 3;
-
- QOpenGLFunctions *funcs = ctx->functions();
-
- if (hasUnpackRowLength) {
- funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, strideInPixels);
- } else if (strideInPixels != image.width()) {
- // No UNPACK_ROW_LENGTH on ES 2.0 and yet we would need it. This case is typically
- // hit with QtWayland which is rarely used in combination with a ES2.0-only GL
- // implementation. Therefore, accept the performance hit and do a copy.
- image = image.copy();
- }
-
- if (resized) {
- if (d_ptr->textureId)
- funcs->glDeleteTextures(1, &d_ptr->textureId);
- funcs->glGenTextures(1, &d_ptr->textureId);
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
- funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
- }
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, imageSize.width(), imageSize.height(), 0, GL_RGBA, pixelType,
- const_cast<uchar*>(image.constBits()));
- } else {
- funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
- QRect imageRect = image.rect();
- QRect rect = dirtyRegion.boundingRect() & imageRect;
-
- if (hasUnpackRowLength) {
- funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
- image.constScanLine(rect.y()) + rect.x() * bytesPerPixel);
- } else {
- // if the rect is wide enough it's cheaper to just
- // extend it instead of doing an image copy
- if (rect.width() >= imageRect.width() / 2) {
- rect.setX(0);
- rect.setWidth(imageRect.width());
- }
-
- // if the sub-rect is full-width we can pass the image data directly to
- // OpenGL instead of copying, since there's no gap between scanlines
-
- if (rect.width() == imageRect.width()) {
- funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
- image.constScanLine(rect.y()));
- } else {
- funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
- image.copy(rect).constBits());
- }
- }
- }
-
- if (hasUnpackRowLength)
- funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-
- return d_ptr->textureId;
}
#endif // QT_NO_OPENGL
@@ -706,6 +317,18 @@ QBackingStore *QPlatformBackingStore::backingStore() const
return d_ptr->backingStore;
}
+#ifndef QT_NO_OPENGL
+/*!
+ Injects an OpenGL implementation helper. Platform integrations need to
+ call this if they intend to use the default OpenGL implementations of
+ composeAndFlush or toTexture.
+*/
+void QPlatformBackingStore::setOpenGLSupport(QPlatformBackingStoreOpenGLSupportBase *openGLSupport)
+{
+ d_ptr->openGLSupport = openGLSupport;
+}
+#endif // QT_NO_OPENGL
+
/*!
This function is called before painting onto the surface begins,
with the \a region in which the painting will occur.
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index 7aa054f1e2..2a3d7d20b5 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -67,11 +67,10 @@ class QRect;
class QPoint;
class QImage;
class QPlatformBackingStorePrivate;
-class QPlatformWindow;
class QPlatformTextureList;
class QPlatformTextureListPrivate;
-class QOpenGLContext;
class QPlatformGraphicsBuffer;
+class QPlatformBackingStoreOpenGLSupportBase;
#ifndef QT_NO_OPENGL
class Q_GUI_EXPORT QPlatformTextureList : public QObject
@@ -118,6 +117,8 @@ public:
QWindow *window() const;
QBackingStore *backingStore() const;
+ void setOpenGLSupport(QPlatformBackingStoreOpenGLSupportBase *openGLSupport);
+
virtual QPaintDevice *paintDevice() = 0;
virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset) = 0;
@@ -154,6 +155,17 @@ private:
};
#ifndef QT_NO_OPENGL
+class Q_GUI_EXPORT QPlatformBackingStoreOpenGLSupportBase // pure interface
+{
+public:
+ virtual void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
+ QPlatformTextureList *textures, bool translucentBackground) = 0;
+ virtual GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, QPlatformBackingStore::TextureFlags *flags) const = 0;
+ virtual ~QPlatformBackingStoreOpenGLSupportBase() {}
+};
+#endif // QT_NO_OPENGL
+
+#ifndef QT_NO_OPENGL
Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformBackingStore::TextureFlags)
#endif
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index ba9590ec07..2a5d7edbee 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -24,6 +24,7 @@ HEADERS += \
qopengltexture.h \
qopengltexture_p.h \
qopengltexturehelper_p.h \
+ qopengltextureblitter.h \
qopengltexturecache_p.h \
qopengltextureglyphcache_p.h \
qopengltextureuploader_p.h \
@@ -40,6 +41,7 @@ SOURCES += \
qopenglpixeltransferoptions.cpp \
qopengltexture.cpp \
qopengltexturehelper.cpp \
+ qopengltextureblitter.cpp \
qopengltexturecache.cpp \
qopengltextureglyphcache.cpp \
qopengltextureuploader.cpp \
diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/opengl/qopengltextureblitter.cpp
index b709f2f639..ba2eaf7754 100644
--- a/src/gui/opengl/qopengltextureblitter.cpp
+++ b/src/opengl/qopengltextureblitter.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the QtOpenGL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE
\brief The QOpenGLTextureBlitter class provides a convenient way to draw textured quads via OpenGL.
\since 5.8
\ingroup painting-3D
- \inmodule QtGui
+ \inmodule QtOpenGL
Drawing textured quads, in order to get the contents of a texture
onto the screen, is a common operation when developing 2D user
diff --git a/src/gui/opengl/qopengltextureblitter.h b/src/opengl/qopengltextureblitter.h
index 2f7c6b1a0a..1818576085 100644
--- a/src/gui/opengl/qopengltextureblitter.h
+++ b/src/opengl/qopengltextureblitter.h
@@ -3,7 +3,7 @@
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtGui module of the Qt Toolkit.
+** This file is part of the QtOpenGL module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -40,9 +40,7 @@
#ifndef QOPENGLTEXTUREBLITTER_H
#define QOPENGLTEXTUREBLITTER_H
-#include <QtGui/qtguiglobal.h>
-
-#ifndef QT_NO_OPENGL
+#include <QtOpenGL/qtopenglglobal.h>
#include <QtGui/qopengl.h>
#include <QtGui/QMatrix3x3>
@@ -52,7 +50,7 @@ QT_BEGIN_NAMESPACE
class QOpenGLTextureBlitterPrivate;
-class Q_GUI_EXPORT QOpenGLTextureBlitter
+class Q_OPENGL_EXPORT QOpenGLTextureBlitter
{
public:
QOpenGLTextureBlitter();
@@ -89,6 +87,4 @@ private:
QT_END_NAMESPACE
-#endif
-
#endif //QOPENGLTEXTUREBLITTER_H
diff --git a/src/opengl/qopenglwindow.cpp b/src/opengl/qopenglwindow.cpp
index 9328d9b46a..5da20dc559 100644
--- a/src/opengl/qopenglwindow.cpp
+++ b/src/opengl/qopenglwindow.cpp
@@ -40,12 +40,12 @@
#include "qopenglwindow.h"
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
-#include <QtGui/QOpenGLTextureBlitter>
#include <QtGui/private/qpaintdevicewindow_p.h>
#include <QtGui/private/qopenglextensions_p.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/QMatrix4x4>
#include <QtGui/QOffscreenSurface>
+#include <QtOpenGL/QOpenGLTextureBlitter>
#include <QtOpenGL/QOpenGLPaintDevice>
QT_BEGIN_NAMESPACE
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp
new file mode 100644
index 0000000000..5a1ff935b8
--- /dev/null
+++ b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp
@@ -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::Unstretched;
+ case DWRITE_FONT_STRETCH_SEMI_EXPANDED: return QFont::SemiExpanded;
+ case DWRITE_FONT_STRETCH_EXPANDED: return QFont::Expanded;
+ case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: return QFont::ExtraExpanded;
+ case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: return QFont::UltraExpanded;
+ default: return QFont::AnyStretch;
+ }
+}
+
+static QFont::Weight fromDirectWriteWeight(DWRITE_FONT_WEIGHT weight)
+{
+ return QPlatformFontDatabase::weightFromInteger(int(weight));
+}
+
+static DWRITE_FONT_STYLE toDirectWriteStyle(QFont::Style style)
+{
+ switch (style) {
+ case QFont::StyleNormal: return DWRITE_FONT_STYLE_NORMAL;
+ case QFont::StyleOblique: return DWRITE_FONT_STYLE_OBLIQUE;
+ case QFont::StyleItalic: return DWRITE_FONT_STYLE_ITALIC;
+ default: return DWRITE_FONT_STYLE_NORMAL;
+ }
+}
+
+static QFont::Style fromDirectWriteStyle(DWRITE_FONT_STYLE style)
+{
+ switch (style) {
+ case DWRITE_FONT_STYLE_NORMAL: return QFont::StyleNormal;
+ case DWRITE_FONT_STYLE_OBLIQUE: return QFont::StyleOblique;
+ case DWRITE_FONT_STYLE_ITALIC: return QFont::StyleItalic;
+ default: return QFont::StyleNormal;
+ }
+}
+
+void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
+{
+ auto it = m_populatedFonts.find(familyName);
+ IDWriteFontFamily *fontFamily = it != m_populatedFonts.end() ? it.value() : nullptr;
+ if (fontFamily == nullptr) {
+ qCWarning(lcQpaFonts) << "Cannot find" << familyName << "in list of fonts";
+ return;
+ }
+
+ qCDebug(lcQpaFonts) << "Populate family:" << familyName;
+
+ wchar_t defaultLocale[LOCALE_NAME_MAX_LENGTH];
+ bool hasDefaultLocale = GetUserDefaultLocaleName(defaultLocale, LOCALE_NAME_MAX_LENGTH) != 0;
+ wchar_t englishLocale[] = L"en-us";
+
+ static const int SMOOTH_SCALABLE = 0xffff;
+ const QString foundryName; // No such concept.
+ const bool scalable = true;
+ const bool antialias = false;
+ const int size = SMOOTH_SCALABLE;
+
+ IDWriteFontList *matchingFonts;
+ if (SUCCEEDED(fontFamily->GetMatchingFonts(DWRITE_FONT_WEIGHT_REGULAR,
+ DWRITE_FONT_STRETCH_NORMAL,
+ DWRITE_FONT_STYLE_NORMAL,
+ &matchingFonts))) {
+ for (uint j = 0; j < matchingFonts->GetFontCount(); ++j) {
+ IDWriteFont *font;
+ if (SUCCEEDED(matchingFonts->GetFont(j, &font))) {
+ IDWriteFont1 *font1 = nullptr;
+ if (!SUCCEEDED(font->QueryInterface(__uuidof(IDWriteFont1),
+ reinterpret_cast<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
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h
new file mode 100644
index 0000000000..2110043df6
--- /dev/null
+++ b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSDIRECTWRITEFONTDATABASE_P_H
+#define QWINDOWSDIRECTWRITEFONTDATABASE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qwindowsfontdatabasebase_p.h"
+
+#include <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
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
index 36a94724c1..cf5763fdbe 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
@@ -51,7 +51,6 @@
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QtEndian>
-#include <QtCore/QThreadStorage>
#include <QtCore/private/qsystemlibrary_p.h>
#include <QtCore/private/qwinregistry_p.h>
@@ -64,6 +63,7 @@
# include <dwrite.h>
# endif
# include <d2d1.h>
+# include "qwindowsdirectwritefontdatabase_p.h"
#endif
QT_BEGIN_NAMESPACE
@@ -75,40 +75,6 @@ Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
typedef HRESULT (WINAPI *DWriteCreateFactoryType)(DWRITE_FACTORY_TYPE, const IID &, IUnknown **);
-static inline DWriteCreateFactoryType resolveDWriteCreateFactory()
-{
- QSystemLibrary library(QStringLiteral("dwrite"));
- QFunctionPointer result = library.resolve("DWriteCreateFactory");
- if (Q_UNLIKELY(!result)) {
- qWarning("Unable to load dwrite.dll");
- return nullptr;
- }
- return reinterpret_cast<DWriteCreateFactoryType>(result);
-}
-
-static void createDirectWriteFactory(IDWriteFactory **factory)
-{
- *factory = nullptr;
-
- static const DWriteCreateFactoryType dWriteCreateFactory = resolveDWriteCreateFactory();
- if (!dWriteCreateFactory)
- return;
-
- IUnknown *result = NULL;
-#if defined(QT_USE_DIRECTWRITE2)
- dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory2), &result);
-#endif
-
- if (result == NULL) {
- if (FAILED(dWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), &result))) {
- qErrnoWarning("DWriteCreateFactory failed");
- return;
- }
- }
-
- *factory = static_cast<IDWriteFactory *>(result);
-}
-
static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
const QString &familyName = QString(),
bool isColorFont = false)
@@ -131,459 +97,6 @@ static inline bool useDirectWrite(QFont::HintingPreference hintingPreference,
}
#endif // !QT_NO_DIRECTWRITE
-// Helper classes for creating font engines directly from font data
-namespace {
-
-# pragma pack(1)
-
- // Common structure for all formats of the "name" table
- struct NameTable
- {
- quint16 format;
- quint16 count;
- quint16 stringOffset;
- };
-
- struct NameRecord
- {
- quint16 platformID;
- quint16 encodingID;
- quint16 languageID;
- quint16 nameID;
- quint16 length;
- quint16 offset;
- };
-
- struct OffsetSubTable
- {
- quint32 scalerType;
- quint16 numTables;
- quint16 searchRange;
- quint16 entrySelector;
- quint16 rangeShift;
- };
-
- struct TableDirectory
- {
- quint32 identifier;
- quint32 checkSum;
- quint32 offset;
- quint32 length;
- };
-
- struct OS2Table
- {
- quint16 version;
- qint16 avgCharWidth;
- quint16 weightClass;
- quint16 widthClass;
- quint16 type;
- qint16 subscriptXSize;
- qint16 subscriptYSize;
- qint16 subscriptXOffset;
- qint16 subscriptYOffset;
- qint16 superscriptXSize;
- qint16 superscriptYSize;
- qint16 superscriptXOffset;
- qint16 superscriptYOffset;
- qint16 strikeOutSize;
- qint16 strikeOutPosition;
- qint16 familyClass;
- quint8 panose[10];
- quint32 unicodeRanges[4];
- quint8 vendorID[4];
- quint16 selection;
- quint16 firstCharIndex;
- quint16 lastCharIndex;
- qint16 typoAscender;
- qint16 typoDescender;
- qint16 typoLineGap;
- quint16 winAscent;
- quint16 winDescent;
- quint32 codepageRanges[2];
- qint16 height;
- qint16 capHeight;
- quint16 defaultChar;
- quint16 breakChar;
- quint16 maxContext;
- };
-
-# pragma pack()
-
- class EmbeddedFont
- {
- public:
- EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) {}
-
- QString changeFamilyName(const QString &newFamilyName);
- QByteArray data() const { return m_fontData; }
- TableDirectory *tableDirectoryEntry(const QByteArray &tagName);
- QString familyName(TableDirectory *nameTableDirectory = 0);
-
- private:
- QByteArray m_fontData;
- };
-
- TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName)
- {
- Q_ASSERT(tagName.size() == 4);
- quint32 tagId = *(reinterpret_cast<const quint32 *>(tagName.constData()));
- const size_t fontDataSize = m_fontData.size();
- if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable)))
- return 0;
-
- OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
- TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
-
- const size_t tableCount = qFromBigEndian<quint16>(offsetSubTable->numTables);
- if (Q_UNLIKELY(fontDataSize < sizeof(OffsetSubTable) + sizeof(TableDirectory) * tableCount))
- return 0;
-
- TableDirectory *tableDirectoryEnd = tableDirectory + tableCount;
- for (TableDirectory *entry = tableDirectory; entry < tableDirectoryEnd; ++entry) {
- if (entry->identifier == tagId)
- return entry;
- }
-
- return 0;
- }
-
- QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry)
- {
- QString name;
-
- if (nameTableDirectoryEntry == 0)
- nameTableDirectoryEntry = tableDirectoryEntry("name");
-
- if (nameTableDirectoryEntry != 0) {
- quint32 offset = qFromBigEndian<quint32>(nameTableDirectoryEntry->offset);
- if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameTable)))
- return QString();
-
- NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data() + offset);
- NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
-
- quint16 nameTableCount = qFromBigEndian<quint16>(nameTable->count);
- if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + sizeof(NameRecord) * nameTableCount))
- return QString();
-
- for (int i = 0; i < nameTableCount; ++i, ++nameRecord) {
- if (qFromBigEndian<quint16>(nameRecord->nameID) == 1
- && qFromBigEndian<quint16>(nameRecord->platformID) == 3 // Windows
- && qFromBigEndian<quint16>(nameRecord->languageID) == 0x0409) { // US English
- quint16 stringOffset = qFromBigEndian<quint16>(nameTable->stringOffset);
- quint16 nameOffset = qFromBigEndian<quint16>(nameRecord->offset);
- quint16 nameLength = qFromBigEndian<quint16>(nameRecord->length);
-
- if (Q_UNLIKELY(quint32(m_fontData.size()) < offset + stringOffset + nameOffset + nameLength))
- return QString();
-
- const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
- + stringOffset
- + nameOffset;
-
- const quint16 *s = reinterpret_cast<const quint16 *>(ptr);
- const quint16 *e = s + nameLength / sizeof(quint16);
- while (s != e)
- name += QChar( qFromBigEndian<quint16>(*s++));
- break;
- }
- }
- }
-
- return name;
- }
-
- QString EmbeddedFont::changeFamilyName(const QString &newFamilyName)
- {
- TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name");
- if (nameTableDirectoryEntry == 0)
- return QString();
-
- QString oldFamilyName = familyName(nameTableDirectoryEntry);
-
- // Reserve size for name table header, five required name records and string
- const int requiredRecordCount = 5;
- quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
-
- int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount;
- int newFamilyNameSize = newFamilyName.size() * int(sizeof(quint16));
-
- const QString regularString = QString::fromLatin1("Regular");
- int regularStringSize = regularString.size() * int(sizeof(quint16));
-
- // Align table size of table to 32 bits (pad with 0)
- int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
-
- QByteArray newNameTable(fullSize, char(0));
-
- {
- NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data());
- nameTable->count = qbswap<quint16>(requiredRecordCount);
- nameTable->stringOffset = qbswap<quint16>(sizeOfHeader);
-
- NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
- for (int i = 0; i < requiredRecordCount; ++i, nameRecord++) {
- nameRecord->nameID = qbswap<quint16>(nameIds[i]);
- nameRecord->encodingID = qbswap<quint16>(1);
- nameRecord->languageID = qbswap<quint16>(0x0409);
- nameRecord->platformID = qbswap<quint16>(3);
- nameRecord->length = qbswap<quint16>(newFamilyNameSize);
-
- // Special case for sub-family
- if (nameIds[i] == 4) {
- nameRecord->offset = qbswap<quint16>(newFamilyNameSize);
- nameRecord->length = qbswap<quint16>(regularStringSize);
- }
- }
-
- // nameRecord now points to string data
- quint16 *stringStorage = reinterpret_cast<quint16 *>(nameRecord);
- const quint16 *sourceString = newFamilyName.utf16();
- for (int i = 0; i < newFamilyName.size(); ++i)
- stringStorage[i] = qbswap<quint16>(sourceString[i]);
- stringStorage += newFamilyName.size();
-
- sourceString = regularString.utf16();
- for (int i = 0; i < regularString.size(); ++i)
- stringStorage[i] = qbswap<quint16>(sourceString[i]);
- }
-
- quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
- quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
-
- quint32 checkSum = 0;
- while (p < tableEnd)
- checkSum += qFromBigEndian<quint32>(*(p++));
-
- nameTableDirectoryEntry->checkSum = qbswap<quint32>(checkSum);
- nameTableDirectoryEntry->offset = qbswap<quint32>(m_fontData.size());
- nameTableDirectoryEntry->length = qbswap<quint32>(fullSize);
-
- m_fontData.append(newNameTable);
-
- return oldFamilyName;
- }
-
-#if !defined(QT_NO_DIRECTWRITE)
-
- class DirectWriteFontFileStream: public IDWriteFontFileStream
- {
- Q_DISABLE_COPY(DirectWriteFontFileStream)
- public:
- DirectWriteFontFileStream(const QByteArray &fontData)
- : m_fontData(fontData)
- , m_referenceCount(0)
- {
- }
- virtual ~DirectWriteFontFileStream()
- {
- }
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
- ULONG STDMETHODCALLTYPE AddRef();
- ULONG STDMETHODCALLTYPE Release();
-
- HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset,
- UINT64 fragmentSize, OUT void **fragmentContext);
- void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext);
- HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize);
- HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime);
-
- private:
- QByteArray m_fontData;
- ULONG m_referenceCount;
- };
-
- HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object)
- {
- if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
- *object = this;
- AddRef();
- return S_OK;
- } else {
- *object = NULL;
- return E_NOINTERFACE;
- }
- }
-
- ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
- {
- return InterlockedIncrement(&m_referenceCount);
- }
-
- ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
- {
- ULONG newCount = InterlockedDecrement(&m_referenceCount);
- if (newCount == 0)
- delete this;
- return newCount;
- }
-
- HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
- const void **fragmentStart,
- UINT64 fileOffset,
- UINT64 fragmentSize,
- OUT void **fragmentContext)
- {
- *fragmentContext = NULL;
- if (fileOffset + fragmentSize <= quint64(m_fontData.size())) {
- *fragmentStart = m_fontData.data() + fileOffset;
- return S_OK;
- } else {
- *fragmentStart = NULL;
- return E_FAIL;
- }
- }
-
- void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *)
- {
- }
-
- HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
- {
- *fileSize = m_fontData.size();
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
- {
- *lastWriteTime = 0;
- return E_NOTIMPL;
- }
-
- class DirectWriteFontFileLoader: public IDWriteFontFileLoader
- {
- public:
- DirectWriteFontFileLoader() : m_referenceCount(0) {}
- virtual ~DirectWriteFontFileLoader()
- {
- }
-
- inline void addKey(const void *key, const QByteArray &fontData)
- {
- Q_ASSERT(!m_fontDatas.contains(key));
- m_fontDatas.insert(key, fontData);
- }
-
- inline void removeKey(const void *key)
- {
- m_fontDatas.remove(key);
- }
-
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
- ULONG STDMETHODCALLTYPE AddRef();
- ULONG STDMETHODCALLTYPE Release();
-
- HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
- UINT32 fontFileReferenceKeySize,
- OUT IDWriteFontFileStream **fontFileStream);
-
- private:
- ULONG m_referenceCount;
- QHash<const void *, QByteArray> m_fontDatas;
- };
-
- HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
- void **object)
- {
- if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
- *object = this;
- AddRef();
- return S_OK;
- } else {
- *object = NULL;
- return E_NOINTERFACE;
- }
- }
-
- ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
- {
- return InterlockedIncrement(&m_referenceCount);
- }
-
- ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
- {
- ULONG newCount = InterlockedDecrement(&m_referenceCount);
- if (newCount == 0)
- delete this;
- return newCount;
- }
-
- HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
- void const *fontFileReferenceKey,
- UINT32 fontFileReferenceKeySize,
- IDWriteFontFileStream **fontFileStream)
- {
- Q_UNUSED(fontFileReferenceKeySize);
-
- if (fontFileReferenceKeySize != sizeof(const void *)) {
- qWarning("%s: Wrong key size", __FUNCTION__);
- return E_FAIL;
- }
-
- const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
- *fontFileStream = NULL;
- auto it = m_fontDatas.constFind(key);
- if (it == m_fontDatas.constEnd())
- return E_FAIL;
-
- QByteArray fontData = it.value();
- DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
- stream->AddRef();
- *fontFileStream = stream;
-
- return S_OK;
- }
-
- class CustomFontFileLoader
- {
- public:
- CustomFontFileLoader() : m_directWriteFontFileLoader(nullptr)
- {
- createDirectWriteFactory(&m_directWriteFactory);
-
- if (m_directWriteFactory) {
- m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
- m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
- }
- }
-
- ~CustomFontFileLoader()
- {
- if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0)
- m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
-
- if (m_directWriteFactory != 0)
- m_directWriteFactory->Release();
- }
-
- void addKey(const void *key, const QByteArray &fontData)
- {
- if (m_directWriteFontFileLoader != 0)
- m_directWriteFontFileLoader->addKey(key, fontData);
- }
-
- void removeKey(const void *key)
- {
- if (m_directWriteFontFileLoader != 0)
- m_directWriteFontFileLoader->removeKey(key);
- }
-
- IDWriteFontFileLoader *loader() const
- {
- return m_directWriteFontFileLoader;
- }
-
- private:
- IDWriteFactory *m_directWriteFactory;
- DirectWriteFontFileLoader *m_directWriteFontFileLoader;
- };
-
-#endif
-
-} // Anonymous namespace
-
/*!
\struct QWindowsFontEngineData
\brief Static constant data shared by the font engines.
@@ -620,18 +133,6 @@ unsigned QWindowsFontDatabase::fontOptions()
return m_fontOptions;
}
-QWindowsFontEngineData::~QWindowsFontEngineData()
-{
- if (hdc)
- DeleteDC(hdc);
-#if !defined(QT_NO_DIRECTWRITE)
- if (directWriteGdiInterop)
- directWriteGdiInterop->Release();
- if (directWriteFactory)
- directWriteFactory->Release();
-#endif
-}
-
qreal QWindowsFontDatabase::fontSmoothingGamma()
{
int winSmooth;
@@ -645,26 +146,6 @@ qreal QWindowsFontDatabase::fontSmoothingGamma()
return result;
}
-#if !defined(QT_NO_DIRECTWRITE)
-static inline bool initDirectWrite(QWindowsFontEngineData *d)
-{
- if (!d->directWriteFactory) {
- createDirectWriteFactory(&d->directWriteFactory);
- if (!d->directWriteFactory)
- return false;
- }
- if (!d->directWriteGdiInterop) {
- const HRESULT hr = d->directWriteFactory->GetGdiInterop(&d->directWriteGdiInterop);
- if (FAILED(hr)) {
- qErrnoWarning("%s: GetGdiInterop failed", __FUNCTION__);
- return false;
- }
- }
- return true;
-}
-
-#endif // !defined(QT_NO_DIRECTWRITE)
-
/*!
\class QWindowsFontDatabase
\brief Font database for Windows
@@ -1239,20 +720,6 @@ void QWindowsFontDatabase::populateFontDatabase()
addDefaultEUDCFont();
}
-typedef QSharedPointer<QWindowsFontEngineData> QWindowsFontEngineDataPtr;
-
-typedef QThreadStorage<QWindowsFontEngineDataPtr> FontEngineThreadLocalData;
-
-Q_GLOBAL_STATIC(FontEngineThreadLocalData, fontEngineThreadLocalData)
-
-QSharedPointer<QWindowsFontEngineData> sharedFontData()
-{
- FontEngineThreadLocalData *data = fontEngineThreadLocalData();
- if (!data->hasLocalData())
- data->setLocalData(QSharedPointer<QWindowsFontEngineData>::create());
- return data->localData();
-}
-
QWindowsFontDatabase::QWindowsFontDatabase()
{
// Properties accessed by QWin32PrintEngine (Qt Print Support)
@@ -1262,9 +729,9 @@ QWindowsFontDatabase::QWindowsFontDatabase()
Q_UNUSED(logFontMetaTypeId)
if (lcQpaFonts().isDebugEnabled()) {
- const QWindowsFontEngineDataPtr data = sharedFontData();
+ QSharedPointer<QWindowsFontEngineData> d = data();
qCDebug(lcQpaFonts) << __FUNCTION__ << "Clear type: "
- << data->clearTypeEnabled << "gamma: " << data->fontSmoothingGamma;
+ << d->clearTypeEnabled << "gamma: " << d->fontSmoothingGamma;
}
}
@@ -1278,7 +745,7 @@ QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *ha
const QString faceName(static_cast<const QChar*>(handle));
QFontEngine *fe = QWindowsFontDatabase::createEngine(fontDef, faceName,
defaultVerticalDPI(),
- sharedFontData());
+ data());
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDEF" << fontDef << fe << handle;
return fe;
}
@@ -1332,7 +799,7 @@ QT_WARNING_POP
fontEngine = QWindowsFontDatabase::createEngine(request, QString(),
defaultVerticalDPI(),
- sharedFontData());
+ data());
if (fontEngine) {
if (request.family != fontEngine->fontDef.family) {
@@ -1371,87 +838,17 @@ QT_WARNING_POP
RemoveFontMemResourceEx(fontHandle);
}
}
+
+ // Get style and weight info
+ if (fontEngine != nullptr)
+ font.updateFromOS2Table(fontEngine);
}
#if !defined(QT_NO_DIRECTWRITE)
else {
- CustomFontFileLoader fontFileLoader;
- fontFileLoader.addKey(this, fontData);
-
- QSharedPointer<QWindowsFontEngineData> fontEngineData = sharedFontData();
- if (!initDirectWrite(fontEngineData.data()))
- return 0;
-
- IDWriteFontFile *fontFile = 0;
- void *key = this;
-
- HRESULT hres = fontEngineData->directWriteFactory->CreateCustomFontFileReference(&key,
- sizeof(void *),
- fontFileLoader.loader(),
- &fontFile);
- if (FAILED(hres)) {
- qErrnoWarning(hres, "%s: CreateCustomFontFileReference failed", __FUNCTION__);
- return 0;
- }
-
- BOOL isSupportedFontType;
- DWRITE_FONT_FILE_TYPE fontFileType;
- DWRITE_FONT_FACE_TYPE fontFaceType;
- UINT32 numberOfFaces;
- fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
- if (!isSupportedFontType) {
- fontFile->Release();
- return 0;
- }
-
- IDWriteFontFace *directWriteFontFace = 0;
- hres = fontEngineData->directWriteFactory->CreateFontFace(fontFaceType,
- 1,
- &fontFile,
- 0,
- DWRITE_FONT_SIMULATIONS_NONE,
- &directWriteFontFace);
- if (FAILED(hres)) {
- qErrnoWarning(hres, "%s: CreateFontFace failed", __FUNCTION__);
- fontFile->Release();
- return 0;
- }
-
- fontFile->Release();
-
- fontEngine = new QWindowsFontEngineDirectWrite(directWriteFontFace,
- pixelSize,
- fontEngineData);
-
- // Get font family from font data
- fontEngine->fontDef.family = font.familyName();
- fontEngine->fontDef.hintingPreference = hintingPreference;
-
- directWriteFontFace->Release();
+ fontEngine = QWindowsFontDatabaseBase::fontEngine(fontData, pixelSize, hintingPreference);
}
#endif
- // Get style and weight info
- if (fontEngine != 0) {
- TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2");
- if (os2TableEntry != 0) {
- const OS2Table *os2Table =
- reinterpret_cast<const OS2Table *>(fontData.constData()
- + qFromBigEndian<quint32>(os2TableEntry->offset));
-
- bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
- bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
-
- if (italic)
- fontEngine->fontDef.style = QFont::StyleItalic;
- else if (oblique)
- fontEngine->fontDef.style = QFont::StyleOblique;
- else
- fontEngine->fontDef.style = QFont::StyleNormal;
-
- fontEngine->fontDef.weight = QPlatformFontDatabase::weightFromInteger(qFromBigEndian<quint16>(os2Table->weightClass));
- }
- }
-
qCDebug(lcQpaFonts) << __FUNCTION__ << "FONTDATA" << fontData << pixelSize << hintingPreference << fontEngine;
return fontEngine;
}
@@ -1683,14 +1080,6 @@ void QWindowsFontDatabase::refUniqueFont(const QString &uniqueFont)
m_uniqueFontData[uniqueFont].refCount.ref();
}
-// ### fixme Qt 6 (QTBUG-58610): See comment at QWindowsFontDatabase::systemDefaultFont()
-HFONT QWindowsFontDatabase::systemFont()
-{
- static const auto stock_sysfont =
- reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
- return stock_sysfont;
-}
-
// Creation functions
static const char *other_tryFonts[] = {
@@ -1745,101 +1134,6 @@ static const char *kr_tryFonts[] = {
static const char **tryFonts = 0;
-LOGFONT QWindowsFontDatabase::fontDefToLOGFONT(const QFontDef &request, const QString &faceName)
-{
- LOGFONT lf;
- memset(&lf, 0, sizeof(LOGFONT));
-
- lf.lfHeight = -qRound(request.pixelSize);
- lf.lfWidth = 0;
- lf.lfEscapement = 0;
- lf.lfOrientation = 0;
- if (request.weight == 50)
- lf.lfWeight = FW_DONTCARE;
- else
- lf.lfWeight = (request.weight*900)/99;
- lf.lfItalic = request.style != QFont::StyleNormal;
- lf.lfCharSet = DEFAULT_CHARSET;
-
- int strat = OUT_DEFAULT_PRECIS;
- if (request.styleStrategy & QFont::PreferBitmap) {
- strat = OUT_RASTER_PRECIS;
- } else if (request.styleStrategy & QFont::PreferDevice) {
- strat = OUT_DEVICE_PRECIS;
- } else if (request.styleStrategy & QFont::PreferOutline) {
- strat = OUT_OUTLINE_PRECIS;
- } else if (request.styleStrategy & QFont::ForceOutline) {
- strat = OUT_TT_ONLY_PRECIS;
- }
-
- lf.lfOutPrecision = strat;
-
- int qual = DEFAULT_QUALITY;
-
- if (request.styleStrategy & QFont::PreferMatch)
- qual = DRAFT_QUALITY;
- else if (request.styleStrategy & QFont::PreferQuality)
- qual = PROOF_QUALITY;
-
- if (request.styleStrategy & QFont::PreferAntialias) {
- qual = (request.styleStrategy & QFont::NoSubpixelAntialias) == 0
- ? CLEARTYPE_QUALITY : ANTIALIASED_QUALITY;
- } else if (request.styleStrategy & QFont::NoAntialias) {
- qual = NONANTIALIASED_QUALITY;
- } else if ((request.styleStrategy & QFont::NoSubpixelAntialias) && sharedFontData()->clearTypeEnabled) {
- qual = ANTIALIASED_QUALITY;
- }
-
- lf.lfQuality = qual;
-
- lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
-
- int hint = FF_DONTCARE;
- switch (request.styleHint) {
- case QFont::Helvetica:
- hint = FF_SWISS;
- break;
- case QFont::Times:
- hint = FF_ROMAN;
- break;
- case QFont::Courier:
- hint = FF_MODERN;
- break;
- case QFont::OldEnglish:
- hint = FF_DECORATIVE;
- break;
- case QFont::System:
- hint = FF_MODERN;
- break;
- default:
- break;
- }
-
- lf.lfPitchAndFamily = DEFAULT_PITCH | hint;
-
- QString fam = faceName;
- if (fam.isEmpty())
- fam = request.families.size() > 0 ? request.families.at(0) : request.family;
- if (Q_UNLIKELY(fam.size() >= LF_FACESIZE)) {
- qCritical("%s: Family name '%s' is too long.", __FUNCTION__, qPrintable(fam));
- fam.truncate(LF_FACESIZE - 1);
- }
-
- if (fam.isEmpty())
- fam = QStringLiteral("MS Sans Serif");
-
- if (fam == QLatin1String("MS Sans Serif")
- && (request.style == QFont::StyleItalic || (-lf.lfHeight > 18 && -lf.lfHeight != 24))) {
- fam = QStringLiteral("Arial"); // MS Sans Serif has bearing problems in italic, and does not scale
- }
- if (fam == QLatin1String("Courier") && !(request.styleStrategy & QFont::PreferBitmap))
- fam = QStringLiteral("Courier New");
-
- memcpy(lf.lfFaceName, fam.utf16(), fam.size() * sizeof(wchar_t));
-
- return lf;
-}
-
QStringList QWindowsFontDatabase::extraTryFontsForFamily(const QString &family)
{
QStringList result;
@@ -1947,7 +1241,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
}
#if !defined(QT_NO_DIRECTWRITE)
- if (initDirectWrite(data.data())) {
+ if (data->directWriteFactory != nullptr) {
const QString fam = QString::fromWCharArray(lf.lfFaceName);
const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
if (nameSubstitute != fam) {
@@ -2023,62 +1317,6 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, const Q
return fe;
}
-QFont QWindowsFontDatabase::systemDefaultFont()
-{
-#if QT_VERSION >= 0x060000
- // Qt 6: Obtain default GUI font (typically "Segoe UI, 9pt", see QTBUG-58610)
- NONCLIENTMETRICS ncm;
- ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
- SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize , &ncm, 0);
- const QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(ncm.lfMessageFont);
-#else
- LOGFONT lf;
- GetObject(QWindowsFontDatabase::systemFont(), sizeof(lf), &lf);
- QFont systemFont = QWindowsFontDatabase::LOGFONT_to_QFont(lf);
- // "MS Shell Dlg 2" is the correct system font >= Win2k
- if (systemFont.family() == QLatin1String("MS Shell Dlg"))
- systemFont.setFamily(QStringLiteral("MS Shell Dlg 2"));
- // Qt 5 by (Qt 4) legacy uses GetStockObject(DEFAULT_GUI_FONT) to
- // obtain the default GUI font (typically "MS Shell Dlg 2, 8pt"). This has been
- // long deprecated; the message font of the NONCLIENTMETRICS structure obtained by
- // SystemParametersInfo(SPI_GETNONCLIENTMETRICS) should be used instead (see
- // QWindowsTheme::refreshFonts(), typically "Segoe UI, 9pt"), which is larger.
-#endif // Qt 5
- qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont;
- return systemFont;
-}
-
-QFont QWindowsFontDatabase::LOGFONT_to_QFont(const LOGFONT& logFont, int verticalDPI_In)
-{
- if (verticalDPI_In <= 0)
- verticalDPI_In = defaultVerticalDPI();
- QFont qFont(QString::fromWCharArray(logFont.lfFaceName));
- qFont.setItalic(logFont.lfItalic);
- if (logFont.lfWeight != FW_DONTCARE)
- qFont.setWeight(QPlatformFontDatabase::weightFromInteger(logFont.lfWeight));
- const qreal logFontHeight = qAbs(logFont.lfHeight);
- qFont.setPointSizeF(logFontHeight * 72.0 / qreal(verticalDPI_In));
- qFont.setUnderline(logFont.lfUnderline);
- qFont.setOverline(false);
- qFont.setStrikeOut(logFont.lfStrikeOut);
- return qFont;
-}
-
-int QWindowsFontDatabase::defaultVerticalDPI()
-{
- static int vDPI = -1;
- if (vDPI == -1) {
- if (HDC defaultDC = GetDC(0)) {
- vDPI = GetDeviceCaps(defaultDC, LOGPIXELSY);
- ReleaseDC(0, defaultDC);
- } else {
- // FIXME: Resolve now or return 96 and keep unresolved?
- vDPI = 96;
- }
- }
- return vDPI;
-}
-
bool QWindowsFontDatabase::isPrivateFontFamily(const QString &family) const
{
return m_eudcFonts.contains(family) || QPlatformFontDatabase::isPrivateFontFamily(family);
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
index f132e69d4d..a76fdc0810 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
@@ -51,39 +51,16 @@
// We mean it.
//
+#include "qwindowsfontdatabasebase_p.h"
+
#include <qpa/qplatformfontdatabase.h>
#include <QtCore/QSharedPointer>
#include <QtCore/QLoggingCategory>
#include <QtCore/qt_windows.h>
-#if !defined(QT_NO_DIRECTWRITE)
- struct IDWriteFactory;
- struct IDWriteGdiInterop;
-#endif
-
QT_BEGIN_NAMESPACE
-Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts)
-
-class QWindowsFontEngineData
-{
- Q_DISABLE_COPY_MOVE(QWindowsFontEngineData)
-public:
- QWindowsFontEngineData();
- ~QWindowsFontEngineData();
-
- uint pow_gamma[256];
-
- bool clearTypeEnabled = false;
- qreal fontSmoothingGamma;
- HDC hdc = 0;
-#if !defined(QT_NO_DIRECTWRITE)
- IDWriteFactory *directWriteFactory = nullptr;
- IDWriteGdiInterop *directWriteGdiInterop = nullptr;
-#endif
-};
-
-class QWindowsFontDatabase : public QPlatformFontDatabase
+class QWindowsFontDatabase : public QWindowsFontDatabaseBase
{
Q_DISABLE_COPY_MOVE(QWindowsFontDatabase)
public:
@@ -113,23 +90,15 @@ public:
void refUniqueFont(const QString &uniqueFont);
bool isPrivateFontFamily(const QString &family) const override;
- static QFont systemDefaultFont();
-
static QFontEngine *createEngine(const QFontDef &request, const QString &faceName,
int dpi,
const QSharedPointer<QWindowsFontEngineData> &data);
- static HFONT systemFont();
- static QFont LOGFONT_to_QFont(const LOGFONT& lf, int verticalDPI = 0);
-
static qreal fontSmoothingGamma();
- static LOGFONT fontDefToLOGFONT(const QFontDef &fontDef, const QString &faceName);
static QStringList extraTryFontsForFamily(const QString &family);
static QString familyForStyleHint(QFont::StyleHint styleHint);
- static int defaultVerticalDPI();
-
static void setFontOptions(unsigned options);
static unsigned fontOptions();
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp
new file mode 100644
index 0000000000..ff46866cb0
--- /dev/null
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase.cpp
@@ -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
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h
new file mode 100644
index 0000000000..004889ab86
--- /dev/null
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabasebase_p.h
@@ -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
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
index 5c999f455e..45ce396d5e 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
@@ -187,6 +187,18 @@ namespace {
}
+static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE renderMode)
+{
+ switch (renderMode) {
+ case DWRITE_RENDERING_MODE_GDI_CLASSIC:
+ return DWRITE_MEASURING_MODE_GDI_CLASSIC;
+ case DWRITE_RENDERING_MODE_GDI_NATURAL:
+ return DWRITE_MEASURING_MODE_GDI_NATURAL;
+ default:
+ return DWRITE_MEASURING_MODE_NATURAL;
+ }
+}
+
static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPreference hintingPreference)
{
if (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting)
@@ -209,13 +221,10 @@ static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(QFont::HintingPref
\ingroup qt-lighthouse-win
Font engine for subpixel positioned text on Windows Vista
- (with platform update) and Windows 7. If selected during
+ (with platform update) and later. If selected during
configuration, the engine will be selected only when the hinting
- preference of a font is set to None or Vertical hinting. The font
- database uses most of the same logic but creates a direct write
- font based on the LOGFONT rather than a GDI handle.
-
- Will probably be superseded by a common Free Type font engine in Qt 5.X.
+ preference of a font is set to None or Vertical hinting, or
+ when fontengine=directwrite is selected as platform option.
*/
QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
@@ -480,9 +489,22 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
glyphIndices[i] = UINT16(glyphs->glyphs[i]);
QVarLengthArray<DWRITE_GLYPH_METRICS> glyphMetrics(glyphIndices.size());
- HRESULT hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
- glyphIndices.size(),
- glyphMetrics.data());
+
+ HRESULT hr;
+ DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
+ if (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL) {
+ hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize),
+ 1.0f,
+ NULL,
+ TRUE,
+ glyphIndices.data(),
+ glyphIndices.size(),
+ glyphMetrics.data());
+ } else {
+ hr = m_directWriteFontFace->GetDesignGlyphMetrics(glyphIndices.data(),
+ glyphIndices.size(),
+ glyphMetrics.data());
+ }
if (SUCCEEDED(hr)) {
qreal stretch = fontDef.stretch != QFont::AnyStretch ? fontDef.stretch / 100.0 : 1.0;
for (int i = 0; i < glyphs->numGlyphs; ++i)
@@ -688,6 +710,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
DWRITE_RENDERING_MODE renderMode =
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
+ DWRITE_MEASURING_MODE measureMode =
+ renderModeToMeasureMode(renderMode);
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
@@ -695,7 +719,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
1.0f,
&transform,
renderMode,
- DWRITE_MEASURING_MODE_NATURAL,
+ measureMode,
0.0, 0.0,
&glyphAnalysis
);
@@ -725,7 +749,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
0.0f,
&glyphRun,
NULL,
- DWRITE_MEASURING_MODE_NATURAL,
+ measureMode,
NULL,
0,
&enumerator);
@@ -756,7 +780,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
1.0f,
&transform,
renderMode,
- DWRITE_MEASURING_MODE_NATURAL,
+ measureMode,
0.0, 0.0,
&colorGlyphsAnalysis
);
@@ -996,6 +1020,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
DWRITE_RENDERING_MODE renderMode =
hintingPreferenceToRenderingMode(QFont::HintingPreference(fontDef.hintingPreference));
+ DWRITE_MEASURING_MODE measureMode = renderModeToMeasureMode(renderMode);
IDWriteGlyphRunAnalysis *glyphAnalysis = NULL;
HRESULT hr = m_fontEngineData->directWriteFactory->CreateGlyphRunAnalysis(
@@ -1003,7 +1028,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
1.0f,
&transform,
renderMode,
- DWRITE_MEASURING_MODE_NATURAL,
+ measureMode,
0.0, 0.0,
&glyphAnalysis
);
diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri
index 7ddfb2c281..fbe6d490f9 100644
--- a/src/platformsupport/fontdatabases/windows/windows.pri
+++ b/src/platformsupport/fontdatabases/windows/windows.pri
@@ -2,11 +2,13 @@ QT *= gui-private
SOURCES += \
$$PWD/qwindowsfontdatabase.cpp \
+ $$PWD/qwindowsfontdatabasebase.cpp \
$$PWD/qwindowsfontengine.cpp \
$$PWD/qwindowsnativeimage.cpp
HEADERS += \
$$PWD/qwindowsfontdatabase_p.h \
+ $$PWD/qwindowsfontdatabasebase_p.h \
$$PWD/qwindowsfontengine_p.h \
$$PWD/qwindowsnativeimage_p.h
@@ -16,7 +18,13 @@ qtConfig(freetype) {
}
qtConfig(directwrite):qtConfig(direct2d) {
- qtConfig(directwrite2) {
+ qtConfig(directwrite3) {
+ QMAKE_USE_PRIVATE += dwrite_3
+ DEFINES *= QT_USE_DIRECTWRITE3 QT_USE_DIRECTWRITE2
+
+ SOURCES += $$PWD/qwindowsdirectwritefontdatabase.cpp
+ HEADERS += $$PWD/qwindowsdirectwritefontdatabase_p.h
+ } else: qtConfig(directwrite2) {
QMAKE_USE_PRIVATE += dwrite_2
DEFINES *= QT_USE_DIRECTWRITE2
} else {
diff --git a/src/platformsupport/platformcompositor/platformcompositor.pro b/src/platformsupport/platformcompositor/platformcompositor.pro
index 81c31571d0..89386ab3ef 100644
--- a/src/platformsupport/platformcompositor/platformcompositor.pro
+++ b/src/platformsupport/platformcompositor/platformcompositor.pro
@@ -1,16 +1,18 @@
TARGET = QtPlatformCompositorSupport
MODULE = platformcompositor_support
-QT = core-private gui-private
+QT = core-private gui-private opengl
CONFIG += static internal_module
DEFINES += QT_NO_CAST_FROM_ASCII
SOURCES += \
+ qplatformbackingstoreopenglsupport.cpp \
qopenglcompositor.cpp \
qopenglcompositorbackingstore.cpp
HEADERS += \
+ qplatformbackingstoreopenglsupport.h \
qopenglcompositor_p.h \
qopenglcompositorbackingstore_p.h
diff --git a/src/platformsupport/platformcompositor/qopenglcompositor_p.h b/src/platformsupport/platformcompositor/qopenglcompositor_p.h
index 41a3288240..c9414c82c6 100644
--- a/src/platformsupport/platformcompositor/qopenglcompositor_p.h
+++ b/src/platformsupport/platformcompositor/qopenglcompositor_p.h
@@ -52,7 +52,7 @@
//
#include <QtCore/QTimer>
-#include <QtGui/QOpenGLTextureBlitter>
+#include <QtOpenGL/QOpenGLTextureBlitter>
#include <QtGui/QMatrix4x4>
QT_BEGIN_NAMESPACE
diff --git a/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp b/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp
new file mode 100644
index 0000000000..ca50910114
--- /dev/null
+++ b/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp
@@ -0,0 +1,455 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_OPENGL
+
+#include "qplatformbackingstoreopenglsupport.h"
+
+#include <QtGui/private/qwindow_p.h>
+
+#include <qpa/qplatformgraphicsbuffer.h>
+#include <qpa/qplatformgraphicsbufferhelper.h>
+
+#include <QtOpenGL/QOpenGLTextureBlitter>
+#include <QtGui/qopengl.h>
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOffscreenSurface>
+
+#ifndef GL_TEXTURE_BASE_LEVEL
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#endif
+#ifndef GL_TEXTURE_MAX_LEVEL
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#endif
+#ifndef GL_UNPACK_ROW_LENGTH
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#endif
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#endif
+
+#ifndef GL_FRAMEBUFFER_SRGB
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#endif
+#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE
+#define GL_FRAMEBUFFER_SRGB_CAPABLE 0x8DBA
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static inline QRect deviceRect(const QRect &rect, QWindow *window)
+{
+ QRect deviceRect(rect.topLeft() * window->devicePixelRatio(),
+ rect.size() * window->devicePixelRatio());
+ return deviceRect;
+}
+
+static inline QPoint deviceOffset(const QPoint &pt, QWindow *window)
+{
+ return pt * window->devicePixelRatio();
+}
+
+static QRegion deviceRegion(const QRegion &region, QWindow *window, const QPoint &offset)
+{
+ if (offset.isNull() && window->devicePixelRatio() <= 1)
+ return region;
+
+ QVector<QRect> rects;
+ rects.reserve(region.rectCount());
+ for (const QRect &rect : region)
+ rects.append(deviceRect(rect.translated(offset), window));
+
+ QRegion deviceRegion;
+ deviceRegion.setRects(rects.constData(), rects.count());
+ return deviceRegion;
+}
+
+static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
+{
+ return QRect(topLeftRect.x(), windowHeight - topLeftRect.bottomRight().y() - 1,
+ topLeftRect.width(), topLeftRect.height());
+}
+
+static void blitTextureForWidget(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect,
+ QOpenGLTextureBlitter *blitter, const QPoint &offset, bool canUseSrgb)
+{
+ const QRect clipRect = textures->clipRect(idx);
+ if (clipRect.isEmpty())
+ return;
+
+ QRect rectInWindow = textures->geometry(idx);
+ // relative to the TLW, not necessarily our window (if the flush is for a native child widget), have to adjust
+ rectInWindow.translate(-offset);
+
+ const QRect clippedRectInWindow = rectInWindow & clipRect.translated(rectInWindow.topLeft());
+ const QRect srcRect = toBottomLeftRect(clipRect, rectInWindow.height());
+
+ const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(deviceRect(clippedRectInWindow, window),
+ deviceWindowRect);
+
+ const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(deviceRect(srcRect, window),
+ deviceRect(rectInWindow, window).size(),
+ QOpenGLTextureBlitter::OriginBottomLeft);
+
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ const bool srgb = textures->flags(idx).testFlag(QPlatformTextureList::TextureIsSrgb);
+ if (srgb && canUseSrgb)
+ funcs->glEnable(GL_FRAMEBUFFER_SRGB);
+
+ blitter->blit(textures->textureId(idx), target, source);
+
+ if (srgb && canUseSrgb)
+ funcs->glDisable(GL_FRAMEBUFFER_SRGB);
+}
+
+QPlatformBackingStoreOpenGLSupport::~QPlatformBackingStoreOpenGLSupport() {
+ if (context) {
+ QOffscreenSurface offscreenSurface;
+ offscreenSurface.setFormat(context->format());
+ offscreenSurface.create();
+ context->makeCurrent(&offscreenSurface);
+ if (textureId)
+ context->functions()->glDeleteTextures(1, &textureId);
+ if (blitter)
+ blitter->destroy();
+ }
+ delete blitter;
+}
+
+void QPlatformBackingStoreOpenGLSupport::composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset, QPlatformTextureList *textures, bool translucentBackground)
+{
+ if (!qt_window_private(window)->receivedExpose)
+ return;
+
+ if (!context) {
+ context.reset(new QOpenGLContext);
+ context->setFormat(window->requestedFormat());
+ context->setScreen(window->screen());
+ context->setShareContext(qt_window_private(window)->shareContext());
+ if (!context->create()) {
+ qCWarning(lcQpaBackingStore, "composeAndFlush: QOpenGLContext creation failed");
+ return;
+ }
+ }
+
+ bool current = context->makeCurrent(window);
+
+ if (!current && context->isValid()) {
+ delete blitter;
+ blitter = nullptr;
+ textureId = 0;
+ current = context->create() && context->makeCurrent(window);
+ }
+
+ if (!current) {
+ qCWarning(lcQpaBackingStore, "composeAndFlush: makeCurrent() failed");
+ return;
+ }
+
+ qCDebug(lcQpaBackingStore) << "Composing and flushing" << region << "of" << window
+ << "at offset" << offset << "with" << textures->count() << "texture(s) in" << textures;
+
+ QWindowPrivate::get(window)->lastComposeTime.start();
+
+ QOpenGLFunctions *funcs = context->functions();
+ funcs->glViewport(0, 0, qRound(window->width() * window->devicePixelRatio()), qRound(window->height() * window->devicePixelRatio()));
+ funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
+ funcs->glClear(GL_COLOR_BUFFER_BIT);
+
+ if (!blitter) {
+ blitter = new QOpenGLTextureBlitter;
+ blitter->create();
+ }
+
+ blitter->bind();
+
+ const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window);
+ const QPoint deviceWindowOffset = deviceOffset(offset, window);
+
+ bool canUseSrgb = false;
+ // If there are any sRGB textures in the list, check if the destination
+ // framebuffer is sRGB capable.
+ for (int i = 0; i < textures->count(); ++i) {
+ if (textures->flags(i).testFlag(QPlatformTextureList::TextureIsSrgb)) {
+ GLint cap = 0;
+ funcs->glGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE, &cap);
+ if (cap)
+ canUseSrgb = true;
+ break;
+ }
+ }
+
+ // Textures for renderToTexture widgets.
+ for (int i = 0; i < textures->count(); ++i) {
+ if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
+ blitTextureForWidget(textures, i, window, deviceWindowRect, blitter, offset, canUseSrgb);
+ }
+
+ // Backingstore texture with the normal widgets.
+ GLuint textureId = 0;
+ QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft;
+ if (QPlatformGraphicsBuffer *graphicsBuffer = backingStore->graphicsBuffer()) {
+ if (graphicsBuffer->size() != textureSize) {
+ if (this->textureId)
+ funcs->glDeleteTextures(1, &this->textureId);
+ funcs->glGenTextures(1, &this->textureId);
+ funcs->glBindTexture(GL_TEXTURE_2D, this->textureId);
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ }
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &needsSwizzle, &premultiplied)) {
+ textureSize = graphicsBuffer->size();
+ } else {
+ textureSize = QSize(0,0);
+ }
+
+ graphicsBuffer->unlock();
+ } else if (!region.isEmpty()){
+ funcs->glBindTexture(GL_TEXTURE_2D, this->textureId);
+ QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &needsSwizzle, &premultiplied);
+ graphicsBuffer->unlock();
+ }
+
+ if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
+ origin = QOpenGLTextureBlitter::OriginBottomLeft;
+ textureId = this->textureId;
+ } else {
+ QPlatformBackingStore::TextureFlags flags;
+ textureId = backingStore->toTexture(deviceRegion(region, window, offset), &textureSize, &flags);
+ needsSwizzle = (flags & QPlatformBackingStore::TextureSwizzle) != 0;
+ premultiplied = (flags & QPlatformBackingStore::TexturePremultiplied) != 0;
+ if (flags & QPlatformBackingStore::TextureFlip)
+ origin = QOpenGLTextureBlitter::OriginBottomLeft;
+ }
+
+ funcs->glEnable(GL_BLEND);
+ if (premultiplied)
+ funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ else
+ funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+
+ if (textureId) {
+ if (needsSwizzle)
+ blitter->setRedBlueSwizzle(true);
+ // The backingstore is for the entire tlw.
+ // In case of native children offset tells the position relative to the tlw.
+ const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(deviceWindowOffset), textureSize.height());
+ const QMatrix3x3 source = QOpenGLTextureBlitter::sourceTransform(srcRect,
+ textureSize,
+ origin);
+ blitter->blit(textureId, QMatrix4x4(), source);
+ if (needsSwizzle)
+ blitter->setRedBlueSwizzle(false);
+ }
+
+ // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
+ bool blendIsPremultiplied = premultiplied;
+ for (int i = 0; i < textures->count(); ++i) {
+ const QPlatformTextureList::Flags flags = textures->flags(i);
+ if (flags.testFlag(QPlatformTextureList::NeedsPremultipliedAlphaBlending)) {
+ if (!blendIsPremultiplied) {
+ funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ blendIsPremultiplied = true;
+ }
+ } else {
+ if (blendIsPremultiplied) {
+ funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ blendIsPremultiplied = false;
+ }
+ }
+ if (flags.testFlag(QPlatformTextureList::StacksOnTop))
+ blitTextureForWidget(textures, i, window, deviceWindowRect, blitter, offset, canUseSrgb);
+ }
+
+ funcs->glDisable(GL_BLEND);
+ blitter->release();
+
+ context->swapBuffers(window);
+}
+
+GLuint QPlatformBackingStoreOpenGLSupport::toTexture(const QRegion &dirtyRegion, QSize *textureSize, QPlatformBackingStore::TextureFlags *flags) const
+{
+ Q_ASSERT(textureSize);
+ Q_ASSERT(flags);
+
+ QImage image = backingStore->toImage();
+ QSize imageSize = image.size();
+
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ GLenum internalFormat = GL_RGBA;
+ GLuint pixelType = GL_UNSIGNED_BYTE;
+
+ bool needsConversion = false;
+ *flags = { };
+ switch (image.format()) {
+ case QImage::Format_ARGB32_Premultiplied:
+ *flags |= QPlatformBackingStore::TexturePremultiplied;
+ Q_FALLTHROUGH();
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ *flags |= QPlatformBackingStore::TextureSwizzle;
+ break;
+ case QImage::Format_RGBA8888_Premultiplied:
+ *flags |= QPlatformBackingStore::TexturePremultiplied;
+ Q_FALLTHROUGH();
+ case QImage::Format_RGBX8888:
+ case QImage::Format_RGBA8888:
+ break;
+ case QImage::Format_BGR30:
+ case QImage::Format_A2BGR30_Premultiplied:
+ if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ internalFormat = GL_RGB10_A2;
+ *flags |= QPlatformBackingStore::TexturePremultiplied;
+ } else {
+ needsConversion = true;
+ }
+ break;
+ case QImage::Format_RGB30:
+ case QImage::Format_A2RGB30_Premultiplied:
+ if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ internalFormat = GL_RGB10_A2;
+ *flags |= QPlatformBackingStore::TextureSwizzle | QPlatformBackingStore::TexturePremultiplied;
+ } else {
+ needsConversion = true;
+ }
+ break;
+ default:
+ needsConversion = true;
+ break;
+ }
+ if (imageSize.isEmpty()) {
+ *textureSize = imageSize;
+ return 0;
+ }
+
+ // Must rely on the input only, not d_ptr.
+ // With the default composeAndFlush() textureSize is &d_ptr->textureSize.
+ bool resized = *textureSize != imageSize;
+ if (dirtyRegion.isEmpty() && !resized)
+ return textureId;
+
+ *textureSize = imageSize;
+
+ if (needsConversion)
+ image = image.convertToFormat(QImage::Format_RGBA8888);
+
+ // The image provided by the backingstore may have a stride larger than width * 4, for
+ // instance on platforms that manually implement client-side decorations.
+ static const int bytesPerPixel = 4;
+ const int strideInPixels = image.bytesPerLine() / bytesPerPixel;
+ const bool hasUnpackRowLength = !ctx->isOpenGLES() || ctx->format().majorVersion() >= 3;
+
+ QOpenGLFunctions *funcs = ctx->functions();
+
+ if (hasUnpackRowLength) {
+ funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, strideInPixels);
+ } else if (strideInPixels != image.width()) {
+ // No UNPACK_ROW_LENGTH on ES 2.0 and yet we would need it. This case is typically
+ // hit with QtWayland which is rarely used in combination with a ES2.0-only GL
+ // implementation. Therefore, accept the performance hit and do a copy.
+ image = image.copy();
+ }
+
+ if (resized) {
+ if (textureId)
+ funcs->glDeleteTextures(1, &textureId);
+ funcs->glGenTextures(1, &textureId);
+ funcs->glBindTexture(GL_TEXTURE_2D, textureId);
+ if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
+ funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ }
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, imageSize.width(), imageSize.height(), 0, GL_RGBA, pixelType,
+ const_cast<uchar*>(image.constBits()));
+ } else {
+ funcs->glBindTexture(GL_TEXTURE_2D, textureId);
+ QRect imageRect = image.rect();
+ QRect rect = dirtyRegion.boundingRect() & imageRect;
+
+ if (hasUnpackRowLength) {
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
+ image.constScanLine(rect.y()) + rect.x() * bytesPerPixel);
+ } else {
+ // if the rect is wide enough it's cheaper to just
+ // extend it instead of doing an image copy
+ if (rect.width() >= imageRect.width() / 2) {
+ rect.setX(0);
+ rect.setWidth(imageRect.width());
+ }
+
+ // if the sub-rect is full-width we can pass the image data directly to
+ // OpenGL instead of copying, since there's no gap between scanlines
+
+ if (rect.width() == imageRect.width()) {
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
+ image.constScanLine(rect.y()));
+ } else {
+ funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
+ image.copy(rect).constBits());
+ }
+ }
+ }
+
+ if (hasUnpackRowLength)
+ funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
+ return textureId;
+}
+
+#endif // QT_NO_OPENGL
+
+QT_END_NAMESPACE
diff --git a/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.h b/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.h
new file mode 100644
index 0000000000..5523b18f76
--- /dev/null
+++ b/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMBACKINGSTOREOPENGLSUPPORT_H
+#define QPLATFORMBACKINGSTOREOPENGLSUPPORT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the QPA API and is not meant to be used
+// in applications. Usage of this API may make your code
+// source and binary incompatible with future versions of Qt.
+//
+
+#ifndef QT_NO_OPENGL
+
+#include <QtGui/qtguiglobal.h>
+#include <qpa/qplatformbackingstore.h>
+
+#include <QtGui/QOpenGLContext>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLTextureBlitter;
+class QOpenGLBackingStore;
+
+class QPlatformBackingStoreOpenGLSupport : public QPlatformBackingStoreOpenGLSupportBase
+{
+public:
+ explicit QPlatformBackingStoreOpenGLSupport(QPlatformBackingStore *backingStore) : backingStore(backingStore) {}
+ ~QPlatformBackingStoreOpenGLSupport() override;
+ void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
+ QPlatformTextureList *textures, bool translucentBackground) override;
+ GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, QPlatformBackingStore::TextureFlags *flags) const override;
+
+private:
+ QPlatformBackingStore *backingStore = nullptr;
+ QScopedPointer<QOpenGLContext> context;
+ mutable GLuint textureId = 0;
+ mutable QSize textureSize;
+ mutable bool needsSwizzle = false;
+ mutable bool premultiplied = false;
+ QOpenGLTextureBlitter *blitter = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_OPENGL
+
+#endif // QPLATFORMBACKINGSTOREOPENGLSUPPORT_H
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro
index 61cac51633..8ea78f7cba 100644
--- a/src/plugins/platforms/android/android.pro
+++ b/src/plugins/platforms/android/android.pro
@@ -9,6 +9,8 @@ QT += \
qtConfig(vulkan): QT += vulkan_support-private
+qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
+
OTHER_FILES += $$PWD/android.json
INCLUDEPATH += \
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index e0c437be27..ae584965e6 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -43,6 +43,9 @@
#include <QtGui/private/qguiapplication_p.h>
#include <QGuiApplication>
#include <QOpenGLContext>
+#if QT_CONFIG(opengl)
+#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
+#endif
#include <QThread>
#include <QOffscreenSurface>
@@ -275,7 +278,12 @@ QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(Q
{
if (!QtAndroid::activity())
return nullptr;
- return new QAndroidPlatformBackingStore(window);
+
+ auto *backingStore = new QAndroidPlatformBackingStore(window);
+#if QT_CONFIG(opengl)
+ backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
+#endif // QT_CONFIG(opengl)
+ return backingStore;
}
QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index a919963cf4..953346c56e 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -101,6 +101,8 @@ QT += \
qtConfig(vulkan): QT += vulkan_support-private
+qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
+
CONFIG += no_app_extension_api_only
qtHaveModule(widgets) {
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index a77b97f538..b2698b05fe 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -68,6 +68,10 @@
#include <QtFontDatabaseSupport/private/qfontengine_coretext_p.h>
+#if QT_CONFIG(opengl)
+#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
+#endif
+
#ifdef QT_WIDGETS_LIB
#include <QtWidgets/qtwidgetsglobal.h>
#if QT_CONFIG(filedialog)
@@ -324,10 +328,16 @@ QPlatformBackingStore *QCocoaIntegration::createPlatformBackingStore(QWindow *wi
return nullptr;
}
+ QPlatformBackingStore *backingStore = nullptr;
if (platformWindow->view().layer)
- return new QCALayerBackingStore(window);
+ backingStore = new QCALayerBackingStore(window);
else
- return new QNSWindowBackingStore(window);
+ backingStore = new QNSWindowBackingStore(window);
+
+#if QT_CONFIG(opengl)
+ backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
+#endif
+ return backingStore;
}
QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const
diff --git a/src/plugins/platforms/ios/kernel.pro b/src/plugins/platforms/ios/kernel.pro
index 71257d09f7..01e0105223 100644
--- a/src/plugins/platforms/ios/kernel.pro
+++ b/src/plugins/platforms/ios/kernel.pro
@@ -9,6 +9,8 @@ QT += \
core-private gui-private \
clipboard_support-private fontdatabase_support-private graphics_support-private
+qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
+
LIBS += -framework Foundation -framework UIKit -framework QuartzCore -framework AudioToolbox
OBJECTIVE_SOURCES = \
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 9eca0eaad3..d724e65717 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -65,6 +65,10 @@
#import <AudioToolbox/AudioServices.h>
+#if QT_CONFIG(opengl)
+#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
+#endif
+
#include <QtDebug>
QT_BEGIN_NAMESPACE
@@ -186,7 +190,11 @@ QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const
// Used when the QWindow's surface type is set by the client to QSurface::RasterSurface
QPlatformBackingStore *QIOSIntegration::createPlatformBackingStore(QWindow *window) const
{
- return new QIOSBackingStore(window);
+ auto *backingStore = new QIOSBackingStore(window);
+#if QT_CONFIG(opengl)
+ backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
+#endif
+ return backingStore;
}
// Used when the QWindow's surface type is set by the client to QSurface::OpenGLSurface
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
index 6bf0d69770..74890ead82 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -36,7 +36,6 @@
#include <QtGui/private/qwindow_p.h>
#include <QtGui/qopenglcontext.h>
#include <QtGui/qopenglfunctions.h>
-#include <QtGui/qopengltextureblitter.h>
#include <QtGui/qoffscreensurface.h>
#include <QtGui/qpainter.h>
#include <private/qpixmapcache_p.h>
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
index 6b59d87a0a..250d244c9f 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.h
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -33,7 +33,7 @@
#include <QtGui/qregion.h>
#include <qpa/qplatformwindow.h>
-#include <QtGui/qopengltextureblitter.h>
+#include <QtOpenGL/qopengltextureblitter.h>
#include <QtGui/qpalette.h>
#include <QtGui/qpainter.h>
@@ -43,7 +43,6 @@ class QWasmWindow;
class QWasmScreen;
class QOpenGLContext;
class QOpenGLTexture;
-class QOpenGLTextureBlitter;
class QWasmCompositedWindow
{
diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp
index fd53cd0bae..ce83ad4e2f 100644
--- a/src/plugins/platforms/wasm/qwasmintegration.cpp
+++ b/src/plugins/platforms/wasm/qwasmintegration.cpp
@@ -41,6 +41,7 @@
#include "qwasmwindow.h"
#ifndef QT_NO_OPENGL
# include "qwasmbackingstore.h"
+# include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
#endif
#include "qwasmfontdatabase.h"
#if defined(Q_OS_UNIX)
@@ -185,6 +186,7 @@ QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *win
#ifndef QT_NO_OPENGL
QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
QWasmBackingStore *backingStore = new QWasmBackingStore(compositor, window);
+ backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
m_backingStores.insert(window, backingStore);
return backingStore;
#else
diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro
index c8b28fb37d..1aee4a3e58 100644
--- a/src/plugins/platforms/wasm/wasm.pro
+++ b/src/plugins/platforms/wasm/wasm.pro
@@ -4,6 +4,8 @@ QT += \
core-private gui-private \
eventdispatcher_support-private fontdatabase_support-private egl_support-private
+qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
+
# Avoid X11 header collision, use generic EGL native types
DEFINES += QT_EGL_NO_X11
diff --git a/src/plugins/platforms/windows/qwindowsgdiintegration.cpp b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
index c88f669eb5..7e9595321a 100644
--- a/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsgdiintegration.cpp
@@ -45,6 +45,10 @@
#include <QtCore/qdebug.h>
#include <QtGui/private/qpixmap_raster_p.h>
+#if QT_CONFIG(opengl)
+#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
+#endif
+
QT_BEGIN_NAMESPACE
class QWindowsGdiIntegrationPrivate
@@ -73,7 +77,11 @@ QPlatformPixmap *QWindowsGdiIntegration::createPlatformPixmap(QPlatformPixmap::P
QPlatformBackingStore *QWindowsGdiIntegration::createPlatformBackingStore(QWindow *window) const
{
- return new QWindowsBackingStore(window);
+ auto *backingStore = new QWindowsBackingStore(window);
+#ifndef QT_NO_OPENGL
+ backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
+#endif
+ return backingStore;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 4b4047ac0c..77340387d8 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -48,6 +48,9 @@
#include "qwindowsscreen.h"
#include "qwindowstheme.h"
#include "qwindowsservices.h"
+#ifdef QT_USE_DIRECTWRITE3
+#include <QtFontDatabaseSupport/private/qwindowsdirectwritefontdatabase_p.h>
+#endif
#ifndef QT_NO_FREETYPE
# include <QtFontDatabaseSupport/private/qwindowsfontdatabase_ft_p.h>
#endif
@@ -187,7 +190,9 @@ static inline unsigned parseOptions(const QStringList &paramList,
unsigned options = 0;
for (const QString &param : paramList) {
if (param.startsWith(u"fontengine=")) {
- if (param.endsWith(u"freetype")) {
+ if (param.endsWith(u"directwrite")) {
+ options |= QWindowsIntegration::FontDatabaseDirectWrite;
+ } else if (param.endsWith(u"freetype")) {
options |= QWindowsIntegration::FontDatabaseFreeType;
} else if (param.endsWith(u"native")) {
options |= QWindowsIntegration::FontDatabaseNative;
@@ -504,14 +509,17 @@ QWindowsStaticOpenGLContext *QWindowsIntegration::staticOpenGLContext()
QPlatformFontDatabase *QWindowsIntegration::fontDatabase() const
{
if (!d->m_fontDatabase) {
-#ifdef QT_NO_FREETYPE
- d->m_fontDatabase = new QWindowsFontDatabase();
-#else // QT_NO_FREETYPE
+#ifdef QT_USE_DIRECTWRITE3
+ if (d->m_options & QWindowsIntegration::FontDatabaseDirectWrite)
+ d->m_fontDatabase = new QWindowsDirectWriteFontDatabase;
+ else
+#endif
+#ifndef QT_NO_FREETYPE
if (d->m_options & QWindowsIntegration::FontDatabaseFreeType)
d->m_fontDatabase = new QWindowsFontDatabaseFT;
else
- d->m_fontDatabase = new QWindowsFontDatabase;
#endif // QT_NO_FREETYPE
+ d->m_fontDatabase = new QWindowsFontDatabase();
}
return d->m_fontDatabase;
}
diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h
index 1f16d13769..165472ad40 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.h
+++ b/src/plugins/platforms/windows/qwindowsintegration.h
@@ -72,7 +72,8 @@ public:
DetectAltGrModifier = 0x800,
RtlEnabled = 0x1000,
DarkModeWindowFrames = 0x2000,
- DarkModeStyle = 0x4000
+ DarkModeStyle = 0x4000,
+ FontDatabaseDirectWrite = 0x8000
};
explicit QWindowsIntegration(const QStringList &paramList);
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index 50a3bb41a9..8a27bd2770 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -5,6 +5,8 @@ QT += \
eventdispatcher_support-private \
fontdatabase_support-private theme_support-private
+qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
+
qtConfig(accessibility): QT += accessibility_support-private
qtConfig(vulkan): QT += vulkan_support-private
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index 27d3746933..dd8cd80fd9 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -53,6 +53,9 @@
#if QT_CONFIG(accessibility)
# include "uiautomation/qwinrtuiaaccessibility.h"
#endif
+#if QT_CONFIG(opengl)
+#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
+#endif
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
@@ -205,7 +208,11 @@ QPlatformWindow *QWinRTIntegration::createPlatformWindow(QWindow *window) const
QPlatformBackingStore *QWinRTIntegration::createPlatformBackingStore(QWindow *window) const
{
- return new QWinRTBackingStore(window);
+ auto *backingStore = new QWinRTBackingStore(window);
+#if QT_CONFIG(opengl)
+ backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
+#endif
+ return backingStore;
}
QPlatformOpenGLContext *QWinRTIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 43dc8f074c..7ac49f73c4 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -6,6 +6,8 @@ QT += \
core-private gui-private \
fontdatabase_support-private egl_support-private
+qtHaveModule(platformcompositor_support-private): QT += platformcompositor_support-private
+
DEFINES *= QT_NO_CAST_FROM_ASCII __WRL_NO_DEFAULT_LIB__
QMAKE_USE_PRIVATE += d3d11 ws2_32
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 3fd989e1f9..cea0511822 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -61,6 +61,9 @@
#include <QtFontDatabaseSupport/private/qgenericunixfontdatabase_p.h>
#include <QtServiceSupport/private/qgenericunixservices_p.h>
+#if QT_CONFIG(opengl)
+#include <QtPlatformCompositorSupport/qpa/qplatformbackingstoreopenglsupport.h>
+#endif
#include <stdio.h>
@@ -288,16 +291,23 @@ QPlatformOpenGLContext *QXcbIntegration::createPlatformOpenGLContext(QOpenGLCont
QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *window) const
{
- const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
- if (isTrayIconWindow)
- return new QXcbSystemTrayBackingStore(window);
+ QPlatformBackingStore *backingStore = nullptr;
+ const bool isTrayIconWindow = QXcbWindow::isTrayIconWindow(window);
+ if (isTrayIconWindow) {
+ backingStore = new QXcbSystemTrayBackingStore(window);
#if QT_CONFIG(xcb_native_painting)
- if (nativePaintingEnabled())
- return new QXcbNativeBackingStore(window);
+ } else if (nativePaintingEnabled()) {
+ backingStore = new QXcbNativeBackingStore(window);
#endif
-
- return new QXcbBackingStore(window);
+ } else {
+ backingStore = new QXcbBackingStore(window);
+ }
+ Q_ASSERT(backingStore);
+#ifndef QT_NO_OPENGL
+ backingStore->setOpenGLSupport(new QPlatformBackingStoreOpenGLSupport(backingStore));
+#endif
+ return backingStore;
}
QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
diff --git a/src/plugins/platforms/xcb/xcb_qpa_lib.pro b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
index a5d05faa9c..1f651e7697 100644
--- a/src/plugins/platforms/xcb/xcb_qpa_lib.pro
+++ b/src/plugins/platforms/xcb/xcb_qpa_lib.pro
@@ -9,6 +9,9 @@ QT += \
edid_support-private \
xkbcommon_support-private
+qtHaveModule(platformcompositor_support-private): \
+ QT += platformcompositor_support-private
+
qtHaveModule(linuxaccessibility_support-private): \
QT += linuxaccessibility_support-private
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index f41b0e8ba4..93bc4d8c4e 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -476,7 +476,7 @@ void Generator::generateCode()
QByteArray unqualifiedScope = p.type.left(s);
// The scope may be a namespace for example, so it's only safe to include scopes that are known QObjects (QTBUG-2151)
- QHash<QByteArray, QByteArray>::ConstIterator scopeIt;
+ QMultiHash<QByteArray, QByteArray>::ConstIterator scopeIt;
QByteArray thisScope = cdef->qualified;
do {
diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp
index 7188c81300..5bd1fba272 100644
--- a/src/tools/rcc/rcc.cpp
+++ b/src/tools/rcc/rcc.cpp
@@ -744,10 +744,9 @@ bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file)
const QString filename = nodes.at(nodes.size()-1);
RCCFileInfo *s = new RCCFileInfo(file);
s->m_parent = parent;
- typedef QHash<QString, RCCFileInfo*>::const_iterator ChildConstIterator;
- const ChildConstIterator cbegin = parent->m_children.constFind(filename);
- const ChildConstIterator cend = parent->m_children.constEnd();
- for (ChildConstIterator it = cbegin; it != cend; ++it) {
+ auto cbegin = parent->m_children.constFind(filename);
+ auto cend = parent->m_children.constEnd();
+ for (auto it = cbegin; it != cend; ++it) {
if (it.key() == filename && it.value()->m_language == s->m_language &&
it.value()->m_country == s->m_country) {
for (const QString &name : qAsConst(m_fileNames)) {
@@ -823,7 +822,7 @@ QStringList RCCResourceLibrary::dataFiles() const
pending.push(m_root);
while (!pending.isEmpty()) {
RCCFileInfo *file = pending.pop();
- for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
+ for (auto it = file->m_children.begin();
it != file->m_children.end(); ++it) {
RCCFileInfo *child = it.value();
if (child->m_flags & RCCFileInfo::Directory)
@@ -838,10 +837,9 @@ QStringList RCCResourceLibrary::dataFiles() const
// Determine map of resource identifier (':/newPrefix/images/p1.png') to file via recursion
static void resourceDataFileMapRecursion(const RCCFileInfo *m_root, const QString &path, RCCResourceLibrary::ResourceDataFileMap &m)
{
- typedef QHash<QString, RCCFileInfo*>::const_iterator ChildConstIterator;
const QChar slash = QLatin1Char('/');
- const ChildConstIterator cend = m_root->m_children.constEnd();
- for (ChildConstIterator it = m_root->m_children.constBegin(); it != cend; ++it) {
+ const auto cend = m_root->m_children.constEnd();
+ for (auto it = m_root->m_children.constBegin(); it != cend; ++it) {
const RCCFileInfo *child = it.value();
const QString childName = path + slash + child->m_name;
if (child->m_flags & RCCFileInfo::Directory) {
@@ -1149,8 +1147,7 @@ bool RCCResourceLibrary::writeDataBlobs()
QString errorMessage;
while (!pending.isEmpty()) {
RCCFileInfo *file = pending.pop();
- for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
- it != file->m_children.end(); ++it) {
+ for (auto it = file->m_children.cbegin(); it != file->m_children.cend(); ++it) {
RCCFileInfo *child = it.value();
if (child->m_flags & RCCFileInfo::Directory)
pending.push(child);
@@ -1214,8 +1211,7 @@ bool RCCResourceLibrary::writeDataNames()
qint64 offset = 0;
while (!pending.isEmpty()) {
RCCFileInfo *file = pending.pop();
- for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
- it != file->m_children.end(); ++it) {
+ for (auto it = file->m_children.cbegin(); it != file->m_children.cend(); ++it) {
RCCFileInfo *child = it.value();
if (child->m_flags & RCCFileInfo::Directory)
pending.push(child);
diff --git a/src/widgets/widgets/qabstractbutton.cpp b/src/widgets/widgets/qabstractbutton.cpp
index 7c26b8cc42..77ffda10b0 100644
--- a/src/widgets/widgets/qabstractbutton.cpp
+++ b/src/widgets/widgets/qabstractbutton.cpp
@@ -413,16 +413,8 @@ void QAbstractButtonPrivate::emitClicked()
QPointer<QAbstractButton> guard(q);
emit q->clicked(checked);
#if QT_CONFIG(buttongroup)
- if (guard && group) {
-#if QT_DEPRECATED_SINCE(5, 15)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- emit group->buttonClicked(group->id(q));
- if (guard && group)
-QT_WARNING_POP
-#endif
- emit group->buttonClicked(q);
- }
+ if (guard && group)
+ emit group->buttonClicked(q);
#endif
}
@@ -432,16 +424,8 @@ void QAbstractButtonPrivate::emitPressed()
QPointer<QAbstractButton> guard(q);
emit q->pressed();
#if QT_CONFIG(buttongroup)
- if (guard && group) {
-#if QT_DEPRECATED_SINCE(5, 15)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- emit group->buttonPressed(group->id(q));
- if (guard && group)
-QT_WARNING_POP
-#endif
- emit group->buttonPressed(q);
- }
+ if (guard && group)
+ emit group->buttonPressed(q);
#endif
}
@@ -451,16 +435,8 @@ void QAbstractButtonPrivate::emitReleased()
QPointer<QAbstractButton> guard(q);
emit q->released();
#if QT_CONFIG(buttongroup)
- if (guard && group) {
-#if QT_DEPRECATED_SINCE(5, 15)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- emit group->buttonReleased(group->id(q));
- if (guard && group)
-QT_WARNING_POP
-#endif
- emit group->buttonReleased(q);
- }
+ if (guard && group)
+ emit group->buttonReleased(q);
#endif
}
@@ -470,16 +446,8 @@ void QAbstractButtonPrivate::emitToggled(bool checked)
QPointer<QAbstractButton> guard(q);
emit q->toggled(checked);
#if QT_CONFIG(buttongroup)
- if (guard && group) {
-#if QT_DEPRECATED_SINCE(5, 15)
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- emit group->buttonToggled(group->id(q), checked);
- if (guard && group)
-QT_WARNING_POP
-#endif
- emit group->buttonToggled(q, checked);
- }
+ if (guard && group)
+ emit group->buttonToggled(q, checked);
#endif
}
diff --git a/src/widgets/widgets/qbuttongroup.cpp b/src/widgets/widgets/qbuttongroup.cpp
index 9162029cdb..1368c721ad 100644
--- a/src/widgets/widgets/qbuttongroup.cpp
+++ b/src/widgets/widgets/qbuttongroup.cpp
@@ -163,16 +163,6 @@ void QButtonGroup::setExclusive(bool exclusive)
*/
/*!
- \fn void QButtonGroup::buttonClicked(int id)
- \obsolete
-
- This signal is emitted when a button with the given \a id is
- clicked.
-
- \sa checkedButton(), QAbstractButton::clicked()
-*/
-
-/*!
\fn void QButtonGroup::buttonPressed(QAbstractButton *button)
\since 4.2
@@ -182,17 +172,6 @@ void QButtonGroup::setExclusive(bool exclusive)
*/
/*!
- \fn void QButtonGroup::buttonPressed(int id)
- \since 4.2
- \obsolete
-
- This signal is emitted when a button with the given \a id is
- pressed down.
-
- \sa QAbstractButton::pressed()
-*/
-
-/*!
\fn void QButtonGroup::buttonReleased(QAbstractButton *button)
\since 4.2
@@ -202,17 +181,6 @@ void QButtonGroup::setExclusive(bool exclusive)
*/
/*!
- \fn void QButtonGroup::buttonReleased(int id)
- \since 4.2
- \obsolete
-
- This signal is emitted when a button with the given \a id is
- released.
-
- \sa QAbstractButton::released()
-*/
-
-/*!
\fn void QButtonGroup::buttonToggled(QAbstractButton *button, bool checked)
\since 5.2
@@ -222,17 +190,6 @@ void QButtonGroup::setExclusive(bool exclusive)
\sa QAbstractButton::toggled()
*/
-/*!
- \fn void QButtonGroup::buttonToggled(int id, bool checked)
- \since 5.2
- \obsolete
-
- This signal is emitted when a button with the given \a id is toggled.
- \a checked is true if the button is checked, or false if the button is unchecked.
-
- \sa QAbstractButton::toggled()
-*/
-
/*!
Adds the given \a button to the button group. If \a id is -1,
diff --git a/src/widgets/widgets/qbuttongroup.h b/src/widgets/widgets/qbuttongroup.h
index 2989dcb4ba..838bf8abce 100644
--- a/src/widgets/widgets/qbuttongroup.h
+++ b/src/widgets/widgets/qbuttongroup.h
@@ -81,16 +81,6 @@ Q_SIGNALS:
void buttonPressed(QAbstractButton *);
void buttonReleased(QAbstractButton *);
void buttonToggled(QAbstractButton *, bool);
-#if QT_DEPRECATED_SINCE(5, 15)
- QT_DEPRECATED_VERSION_X_5_15("Use QButtonGroup::buttonClicked(QAbstractButton *) instead")
- void buttonClicked(int);
- QT_DEPRECATED_VERSION_X_5_15("Use QButtonGroup::buttonPressed(QAbstractButton *) instead")
- void buttonPressed(int);
- QT_DEPRECATED_VERSION_X_5_15("Use QButtonGroup::buttonReleased(QAbstractButton *) instead")
- void buttonReleased(int);
- QT_DEPRECATED_VERSION_X_5_15("Use QButtonGroup::buttonToggled(QAbstractButton *, bool) instead")
- void buttonToggled(int, bool);
-#endif
private:
Q_DISABLE_COPY(QButtonGroup)
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index 3da7e365c8..f8bccfbfa3 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -2512,7 +2512,7 @@ void QWidgetTextControl::setExtraSelections(const QList<QTextEdit::ExtraSelectio
emit updateRequest(r);
}
- for (QHash<int, int>::iterator it = hash.begin(); it != hash.end(); ++it) {
+ for (auto it = hash.cbegin(); it != hash.cend(); ++it) {
const QAbstractTextDocumentLayout::Selection &esel = d->extraSelections.at(it.value());
QRectF r = selectionRect(esel.cursor);
if (esel.format.boolProperty(QTextFormat::FullWidthSelection)) {
diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp
index 647e22bf26..1ac13b380a 100644
--- a/src/xml/dom/qdom.cpp
+++ b/src/xml/dom/qdom.cpp
@@ -2550,7 +2550,7 @@ QDomNamedNodeMapPrivate* QDomNamedNodeMapPrivate::clone(QDomNodePrivate* p)
m->readonly = readonly;
m->appendToParent = appendToParent;
- QHash<QString, QDomNodePrivate*>::const_iterator it = map.constBegin();
+ auto it = map.constBegin();
for (; it != map.constEnd(); ++it) {
QDomNodePrivate *new_node = (*it)->cloneNode();
new_node->setParent(p);
@@ -2566,7 +2566,7 @@ void QDomNamedNodeMapPrivate::clearMap()
{
// Dereference all of our children if we took references
if (!appendToParent) {
- QHash<QString, QDomNodePrivate *>::const_iterator it = map.constBegin();
+ auto it = map.constBegin();
for (; it != map.constEnd(); ++it)
if (!(*it)->ref.deref())
delete *it;
@@ -2582,7 +2582,7 @@ QDomNodePrivate* QDomNamedNodeMapPrivate::namedItem(const QString& name) const
QDomNodePrivate* QDomNamedNodeMapPrivate::namedItemNS(const QString& nsURI, const QString& localName) const
{
- QHash<QString, QDomNodePrivate *>::const_iterator it = map.constBegin();
+ auto it = map.constBegin();
QDomNodePrivate *n;
for (; it != map.constEnd(); ++it) {
n = *it;
@@ -3098,11 +3098,11 @@ void QDomDocumentTypePrivate::save(QTextStream& s, int, int indent) const
if (entities->length()>0 || notations->length()>0) {
s << " [" << Qt::endl;
- QHash<QString, QDomNodePrivate *>::const_iterator it2 = notations->map.constBegin();
+ auto it2 = notations->map.constBegin();
for (; it2 != notations->map.constEnd(); ++it2)
(*it2)->save(s, 0, indent);
- QHash<QString, QDomNodePrivate *>::const_iterator it = entities->map.constBegin();
+ auto it = entities->map.constBegin();
for (; it != entities->map.constEnd(); ++it)
(*it)->save(s, 0, indent);
@@ -4088,7 +4088,7 @@ void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const
/* Write out attributes. */
if (!m_attr->map.isEmpty()) {
QDuplicateTracker<QString> outputtedPrefixes;
- QHash<QString, QDomNodePrivate *>::const_iterator it = m_attr->map.constBegin();
+ auto it = m_attr->map.constBegin();
for (; it != m_attr->map.constEnd(); ++it) {
s << ' ';
if (it.value()->namespaceURI.isNull()) {
diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
index 877de3f95d..d1a77173c3 100644
--- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
@@ -121,6 +121,9 @@ private slots:
void stream_Map_data();
void stream_Map();
+ void stream_MultiMap_data();
+ void stream_MultiMap();
+
void stream_Hash_data();
void stream_Hash();
@@ -233,6 +236,7 @@ private:
void writeQRegularExpression(QDataStream *dev);
#endif
void writeMap(QDataStream* dev);
+ void writeMultiMap(QDataStream* dev);
void writeHash(QDataStream* dev);
void writeMultiHash(QDataStream* dev);
void writeqint64(QDataStream *s);
@@ -266,6 +270,7 @@ private:
void readQRegularExpression(QDataStream *s);
#endif
void readMap(QDataStream *s);
+ void readMultiMap(QDataStream *s);
void readHash(QDataStream *s);
void readMultiHash(QDataStream *s);
void readqint64(QDataStream *s);
@@ -655,16 +660,10 @@ static Map MapData(int index)
map.insert(2, "bbb");
map.insert(3, "cccccc");
break;
- case 2:
- map.insert(1, "a");
- map.insert(2, "one");
- map.insertMulti(2, "two");
- map.insertMulti(2, "three");
- map.insert(3, "cccccc");
}
return map;
}
-#define MAX_MAP_DATA 3
+#define MAX_MAP_DATA 2
void tst_QDataStream::stream_Map_data()
{
@@ -694,6 +693,60 @@ void tst_QDataStream::readMap(QDataStream *s)
QCOMPARE(S, test);
}
+typedef QMultiMap<int, QString> MultiMap;
+
+static MultiMap MultiMapData(int index)
+{
+ MultiMap map;
+
+ switch (index) {
+ case 0:
+ default:
+ break;
+ case 1:
+ map.insert(1, "a");
+ map.insert(2, "bbb");
+ map.insert(3, "cccccc");
+ break;
+ case 2:
+ map.insert(1, "a");
+ map.insert(2, "one");
+ map.insert(2, "two");
+ map.insert(2, "three");
+ map.insert(3, "cccccc");
+ }
+ return map;
+}
+#define MAX_MULTIMAP_DATA 3
+
+void tst_QDataStream::stream_MultiMap_data()
+{
+ stream_data(MAX_MULTIMAP_DATA);
+}
+
+void tst_QDataStream::stream_MultiMap()
+{
+ STREAM_IMPL(MultiMap);
+}
+
+void tst_QDataStream::writeMultiMap(QDataStream* s)
+{
+ MultiMap test(MultiMapData(dataIndex(QTest::currentDataTag())));
+ *s << test;
+ *s << test;
+}
+
+void tst_QDataStream::readMultiMap(QDataStream *s)
+{
+ MultiMap S;
+ MultiMap test(MultiMapData(dataIndex(QTest::currentDataTag())));
+
+ *s >> S;
+ QCOMPARE(S, test);
+ *s >> S;
+ QCOMPARE(S, test);
+}
+
// ************************************
typedef QHash<int, QString> Hash;
diff --git a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp
index a9fd282ac9..8a621cd5d9 100644
--- a/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp
+++ b/tests/auto/corelib/tools/qsharedpointer/tst_qsharedpointer.cpp
@@ -2155,7 +2155,7 @@ void tst_QSharedPointer::threadStressTest()
}
}
-template<typename Container, bool Ordered>
+template<typename Container, bool Ordered, bool Multi>
void hashAndMapTest()
{
typedef typename Container::key_type Key;
@@ -2200,26 +2200,30 @@ void hashAndMapTest()
QVERIFY(it == c.end());
}
- c.insertMulti(k1, Value(47));
- it = c.find(k1);
- QVERIFY(it != c.end());
- QCOMPARE(it.key(), k1);
- ++it;
- QVERIFY(it != c.end());
- QCOMPARE(it.key(), k1);
- ++it;
- if (Ordered)
- QVERIFY(it == c.end());
+ if (Multi) {
+ c.insert(k1, Value(47));
+ it = c.find(k1);
+ QVERIFY(it != c.end());
+ QCOMPARE(it.key(), k1);
+ ++it;
+ QVERIFY(it != c.end());
+ QCOMPARE(it.key(), k1);
+ ++it;
+ if (Ordered)
+ QVERIFY(it == c.end());
+ }
}
void tst_QSharedPointer::map()
{
- hashAndMapTest<QMap<QSharedPointer<int>, int>, true>();
+ hashAndMapTest<QMap<QSharedPointer<int>, int>, true, false>();
+ hashAndMapTest<QMultiMap<QSharedPointer<int>, int>, true, true>();
}
void tst_QSharedPointer::hash()
{
- hashAndMapTest<QHash<QSharedPointer<int>, int>, false>();
+ hashAndMapTest<QHash<QSharedPointer<int>, int>, false, false>();
+ hashAndMapTest<QMultiHash<QSharedPointer<int>, int>, false, true>();
}
void tst_QSharedPointer::validConstructs()
diff --git a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
index 63a6618dab..928bd365fd 100644
--- a/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
+++ b/tests/auto/corelib/tools/qversionnumber/tst_qversionnumber.cpp
@@ -81,9 +81,10 @@ private slots:
void serialize();
void moveSemantics();
void qtVersion();
- void qPropertyRevision_data();
- void qPropertyRevision();
- void qPropertyRevisionTypes();
+ void qTypeRevision_data();
+ void qTypeRevision();
+ void qTypeRevisionTypes();
+ void qTypeRevisionComparison();
};
void tst_QVersionNumber::singleInstanceData()
@@ -704,7 +705,7 @@ void compileTestRevision<qint8>()
compileTestRevisionMajorMinor<qint8>();
}
-void tst_QVersionNumber::qPropertyRevision_data()
+void tst_QVersionNumber::qTypeRevision_data()
{
QTest::addColumn<QTypeRevision>("revision");
QTest::addColumn<bool>("valid");
@@ -723,7 +724,7 @@ void tst_QVersionNumber::qPropertyRevision_data()
// You must not pass them as major or minor versions, or values.
}
-void tst_QVersionNumber::qPropertyRevision()
+void tst_QVersionNumber::qTypeRevision()
{
const QTypeRevision other = QTypeRevision::fromVersion(127, 128);
@@ -747,7 +748,7 @@ void tst_QVersionNumber::qPropertyRevision()
QVERIFY(copy != other);
}
-void tst_QVersionNumber::qPropertyRevisionTypes()
+void tst_QVersionNumber::qTypeRevisionTypes()
{
compileTestRevision<quint64>();
compileTestRevision<qint64>();
@@ -760,6 +761,41 @@ void tst_QVersionNumber::qPropertyRevisionTypes()
QVERIFY(maxRevision.hasMinorVersion());
}
+void tst_QVersionNumber::qTypeRevisionComparison()
+{
+ const QTypeRevision revisions[] = {
+ QTypeRevision::zero(),
+ QTypeRevision::fromMajorVersion(0),
+ QTypeRevision::fromVersion(0, 1),
+ QTypeRevision::fromVersion(0, 20),
+ QTypeRevision::fromMinorVersion(0),
+ QTypeRevision(),
+ QTypeRevision::fromMinorVersion(1),
+ QTypeRevision::fromMinorVersion(20),
+ QTypeRevision::fromVersion(1, 0),
+ QTypeRevision::fromMajorVersion(1),
+ QTypeRevision::fromVersion(1, 1),
+ QTypeRevision::fromVersion(1, 20),
+ QTypeRevision::fromVersion(20, 0),
+ QTypeRevision::fromMajorVersion(20),
+ QTypeRevision::fromVersion(20, 1),
+ QTypeRevision::fromVersion(20, 20),
+ };
+
+ const int length = sizeof(revisions) / sizeof(QTypeRevision);
+
+ for (int i = 0; i < length; ++i) {
+ for (int j = 0; j < length; ++j) {
+ QCOMPARE(revisions[i] == revisions[j], i == j);
+ QCOMPARE(revisions[i] != revisions[j], i != j);
+ QCOMPARE(revisions[i] < revisions[j], i < j);
+ QCOMPARE(revisions[i] > revisions[j], i > j);
+ QCOMPARE(revisions[i] <= revisions[j], i <= j);
+ QCOMPARE(revisions[i] >= revisions[j], i >= j);
+ }
+ }
+}
+
QTEST_APPLESS_MAIN(tst_QVersionNumber)
#include "tst_qversionnumber.moc"
diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp
index 3a7ad6dad5..cf839e1931 100644
--- a/tests/auto/gui/qopengl/tst_qopengl.cpp
+++ b/tests/auto/gui/qopengl/tst_qopengl.cpp
@@ -28,6 +28,7 @@
#include <QtOpenGL/QOpenGLPaintDevice>
#include <QtOpenGL/QOpenGLTexture>
+#include <QtOpenGL/qopengltextureblitter.h>
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
@@ -40,7 +41,6 @@
#include <QtGui/QOffscreenSurface>
#include <QtGui/QGenericMatrix>
#include <QtGui/QMatrix4x4>
-#include <QtGui/qopengltextureblitter.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qopenglextensions_p.h>
#include <qpa/qplatformintegration.h>
diff --git a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
index 5be00630ca..1ef9382f0a 100644
--- a/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
+++ b/tests/auto/network/socket/platformsocketengine/tst_platformsocketengine.cpp
@@ -530,11 +530,17 @@ void tst_PlatformSocketEngine::tooManySockets()
void tst_PlatformSocketEngine::bind()
{
#if !defined Q_OS_WIN
- PLATFORMSOCKETENGINE binder;
- QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
- QVERIFY(!binder.bind(QHostAddress::AnyIPv4, 82));
- QCOMPARE(binder.error(), QAbstractSocket::SocketAccessError);
-#endif
+#if defined Q_OS_MACOS
+ // On macOS >= 10.14 the bind on this port is successful.
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave)
+#endif // Q_OS_MACOS
+ {
+ PLATFORMSOCKETENGINE binder;
+ QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
+ QVERIFY(!binder.bind(QHostAddress::AnyIPv4, 82));
+ QCOMPARE(binder.error(), QAbstractSocket::SocketAccessError);
+ }
+#endif // Q_OS_WIN
PLATFORMSOCKETENGINE binder2;
QVERIFY(binder2.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol));
diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
index 9ab5e88900..bf08d70eb3 100644
--- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
+++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
@@ -558,8 +558,18 @@ void tst_QTcpSocket::bind_data()
// try to bind to a privileged ports
// we should fail if we're not root (unless the ports are in use!)
QTest::newRow("127.0.0.1:1") << "127.0.0.1" << 1 << !geteuid() << (geteuid() ? QString() : "127.0.0.1");
- if (testIpv6)
+ if (testIpv6) {
+#ifdef Q_OS_DARWIN
+ // This case is faling in different ways, first, it manages to bind to
+ // port 1 on macOS >= 10.14, but if we change the logic to not fail,
+ // it's becoming flaky and sometimes fails to bind, with error 'port in use'
+ // (apparently inflicted by the previous test row with 127.0.0.1). Amen.
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave)
+ QTest::qWarn("Skipping [::]:1, see QTBUG-81905", __FILE__, __LINE__);
+ else
+#endif // Q_OS_DARWIN
QTest::newRow("[::]:1") << "::" << 1 << !geteuid() << (geteuid() ? QString() : "::");
+ }
#endif
}
diff --git a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
index 47dfc86a69..5d52acd1a2 100644
--- a/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
+++ b/tests/auto/widgets/widgets/qbuttongroup/tst_qbuttongroup.cpp
@@ -280,67 +280,43 @@ void tst_QButtonGroup::testSignals()
qRegisterMetaType<QAbstractButton *>("QAbstractButton *");
QSignalSpy clickedSpy(&buttons, SIGNAL(buttonClicked(QAbstractButton*)));
- QSignalSpy clickedIdSpy(&buttons, SIGNAL(buttonClicked(int)));
QSignalSpy pressedSpy(&buttons, SIGNAL(buttonPressed(QAbstractButton*)));
- QSignalSpy pressedIdSpy(&buttons, SIGNAL(buttonPressed(int)));
QSignalSpy releasedSpy(&buttons, SIGNAL(buttonReleased(QAbstractButton*)));
- QSignalSpy releasedIdSpy(&buttons, SIGNAL(buttonReleased(int)));
pb1.animateClick();
QTestEventLoop::instance().enterLoop(1);
QCOMPARE(clickedSpy.count(), 1);
- QCOMPARE(clickedIdSpy.count(), 1);
- int expectedId = -2;
-
- QCOMPARE(clickedIdSpy.takeFirst().at(0).toInt(), expectedId);
QCOMPARE(pressedSpy.count(), 1);
- QCOMPARE(pressedIdSpy.count(), 1);
- QCOMPARE(pressedIdSpy.takeFirst().at(0).toInt(), expectedId);
QCOMPARE(releasedSpy.count(), 1);
- QCOMPARE(releasedIdSpy.count(), 1);
- QCOMPARE(releasedIdSpy.takeFirst().at(0).toInt(), expectedId);
clickedSpy.clear();
- clickedIdSpy.clear();
pressedSpy.clear();
- pressedIdSpy.clear();
releasedSpy.clear();
- releasedIdSpy.clear();
pb2.animateClick();
QTestEventLoop::instance().enterLoop(1);
QCOMPARE(clickedSpy.count(), 1);
- QCOMPARE(clickedIdSpy.count(), 1);
- QCOMPARE(clickedIdSpy.takeFirst().at(0).toInt(), 23);
QCOMPARE(pressedSpy.count(), 1);
- QCOMPARE(pressedIdSpy.count(), 1);
- QCOMPARE(pressedIdSpy.takeFirst().at(0).toInt(), 23);
QCOMPARE(releasedSpy.count(), 1);
- QCOMPARE(releasedIdSpy.count(), 1);
- QCOMPARE(releasedIdSpy.takeFirst().at(0).toInt(), 23);
QSignalSpy toggledSpy(&buttons, SIGNAL(buttonToggled(QAbstractButton*, bool)));
- QSignalSpy toggledIdSpy(&buttons, SIGNAL(buttonToggled(int, bool)));
pb1.setCheckable(true);
pb2.setCheckable(true);
pb1.toggle();
QCOMPARE(toggledSpy.count(), 1);
- QCOMPARE(toggledIdSpy.count(), 1);
pb2.toggle();
QCOMPARE(toggledSpy.count(), 3); // equals 3 since pb1 and pb2 are both toggled
- QCOMPARE(toggledIdSpy.count(), 3);
pb1.setCheckable(false);
pb2.setCheckable(false);
pb1.toggle();
QCOMPARE(toggledSpy.count(), 3);
- QCOMPARE(toggledIdSpy.count(), 3);
}
void tst_QButtonGroup::task106609()
@@ -372,7 +348,6 @@ void tst_QButtonGroup::task106609()
qRegisterMetaType<QAbstractButton*>("QAbstractButton*");
QSignalSpy spy1(buttons, SIGNAL(buttonClicked(QAbstractButton*)));
- QSignalSpy spy2(buttons, SIGNAL(buttonClicked(int)));
QApplication::setActiveWindow(&dlg);
QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget*>(&dlg));
@@ -381,8 +356,6 @@ void tst_QButtonGroup::task106609()
radio1->setChecked(true);
QTestEventLoop::instance().enterLoop(1);
- //qDebug() << "int:" << spy2.count() << "QAbstractButton*:" << spy1.count();
- QCOMPARE(spy2.count(), 2);
QCOMPARE(spy1.count(), 2);
}
@@ -427,11 +400,12 @@ public:
: group(group)
, deleteButton(deleteButton)
{
- connect(group, SIGNAL(buttonClicked(int)), SLOT(buttonClicked(int)));
+ connect(group, &QButtonGroup::buttonClicked,
+ this, &task209485_ButtonDeleter::buttonClicked);
}
private slots:
- void buttonClicked(int)
+ void buttonClicked()
{
if (deleteButton)
group->removeButton(group->buttons().first());
@@ -447,7 +421,7 @@ void tst_QButtonGroup::task209485_removeFromGroupInEventHandler_data()
QTest::addColumn<bool>("deleteButton");
QTest::addColumn<int>("signalCount");
QTest::newRow("buttonPress 1") << true << 1;
- QTest::newRow("buttonPress 2") << false << 2;
+ QTest::newRow("buttonPress 2") << false << 1;
}
void tst_QButtonGroup::task209485_removeFromGroupInEventHandler()
@@ -463,12 +437,11 @@ void tst_QButtonGroup::task209485_removeFromGroupInEventHandler()
task209485_ButtonDeleter buttonDeleter(&group, deleteButton);
QSignalSpy spy1(&group, SIGNAL(buttonClicked(QAbstractButton*)));
- QSignalSpy spy2(&group, SIGNAL(buttonClicked(int)));
// NOTE: Reintroducing the bug of this task will cause the following line to crash:
QTest::mouseClick(button, Qt::LeftButton);
- QCOMPARE(spy1.count() + spy2.count(), signalCount);
+ QCOMPARE(spy1.count(), signalCount);
}
void tst_QButtonGroup::autoIncrementId()