summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Forward Merge Bot <qt_forward_merge_bot@qt-project.org>2020-03-11 01:00:56 +0100
committerSona Kurazyan <sona.kurazyan@qt.io>2020-03-11 15:39:56 +0100
commit3d315860cdf13fe2adf78c8eea07aea10444ed72 (patch)
treeb5a7daa8534b8dadc3abfd665655af3a2450af76
parentcd80f347cf5d40938df7c10d1f6dac3d8c81ff95 (diff)
parent865afac25036d58b18794384e37d42931b2164c5 (diff)
Merge "Merge remote-tracking branch 'origin/5.15' into dev"
-rw-r--r--examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp29
-rw-r--r--examples/corelib/threads/mandelbrot/renderthread.cpp27
-rw-r--r--examples/corelib/threads/mandelbrot/renderthread.h6
-rw-r--r--examples/opengl/paintedwindow/paintedwindow.cpp1
-rw-r--r--examples/opengl/qopenglwindow/main.cpp1
-rw-r--r--examples/qpa/qrasterwindow/main.cpp1
-rw-r--r--examples/sql/doc/src/drilldown.qdoc3
-rw-r--r--examples/sql/drilldown/imageitem.h3
-rw-r--r--examples/widgets/painting/basicdrawing/renderarea.cpp1
-rw-r--r--examples/widgets/widgets/styles/norwegianwoodstyle.cpp1
-rw-r--r--mkspecs/android-clang/qmake.conf3
-rw-r--r--mkspecs/features/android/android_deployment_settings.prf6
-rw-r--r--qmake/doc/src/qmake-manual.qdoc35
-rw-r--r--src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--src/android/templates/AndroidManifest.xml2
-rw-r--r--src/android/templates/build.gradle8
-rw-r--r--src/corelib/Qt5AndroidSupport.cmake5
-rw-r--r--src/corelib/doc/src/dontdocument.qdoc2
-rw-r--r--src/corelib/doc/src/resource-system.qdoc19
-rw-r--r--src/corelib/global/qfloat16.cpp44
-rw-r--r--src/corelib/io/qloggingregistry.cpp40
-rw-r--r--src/corelib/io/qloggingregistry_p.h8
-rw-r--r--src/corelib/io/qprocess.cpp9
-rw-r--r--src/corelib/io/qresource.cpp2
-rw-r--r--src/corelib/kernel/qmetatype.cpp4
-rw-r--r--src/corelib/mimetypes/mimetypes.pri7
-rw-r--r--src/corelib/text/qbytearray.h8
-rw-r--r--src/corelib/text/qstring.cpp40
-rw-r--r--src/corelib/text/qstring.h15
-rw-r--r--src/corelib/text/qstringview.cpp26
-rw-r--r--src/corelib/text/qstringview.h5
-rw-r--r--src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp3
-rw-r--r--src/gui/image/qimage.cpp46
-rw-r--r--src/gui/image/qimage_conversions.cpp209
-rw-r--r--src/gui/painting/qimagescale.cpp794
-rw-r--r--src/gui/painting/qimagescale_neon.cpp218
-rw-r--r--src/gui/painting/qimagescale_p.h2
-rw-r--r--src/gui/painting/qimagescale_sse4.cpp246
-rw-r--r--src/gui/painting/qpainterpath.cpp70
-rw-r--r--src/gui/painting/qpainterpath.h12
-rw-r--r--src/gui/painting/qrasterizer.cpp2
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp2
-rw-r--r--src/gui/painting/qtransform.h5
-rw-r--r--src/gui/rhi/qrhi.cpp66
-rw-r--r--src/gui/rhi/qrhi_p.h11
-rw-r--r--src/gui/rhi/qrhid3d11.cpp282
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h11
-rw-r--r--src/gui/rhi/qrhigles2.cpp61
-rw-r--r--src/gui/rhi/qrhimetal.mm112
-rw-r--r--src/gui/rhi/qrhimetal_p_p.h11
-rw-r--r--src/gui/rhi/qrhivulkan.cpp92
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h11
-rw-r--r--src/gui/text/qrawfont.cpp1
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp2
-rw-r--r--src/gui/vulkan/qvulkanwindow.h2
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp2
-rw-r--r--src/network/access/qnetworkaccessmanager.h15
-rw-r--r--src/network/doc/qtnetwork.qdocconf2
-rw-r--r--src/network/doc/snippets/CMakeLists.txt12
-rw-r--r--src/network/doc/snippets/code/doc_src_qtnetwork.pro3
-rw-r--r--src/network/doc/snippets/network/tcpwait.cpp2
-rw-r--r--src/network/doc/snippets/snippets.pro2
-rw-r--r--src/network/doc/src/bearermanagement.qdoc2
-rw-r--r--src/network/doc/src/qtnetwork.qdoc30
-rw-r--r--src/network/ssl/qsslcertificate.cpp8
-rw-r--r--src/network/ssl/qsslcertificate.h4
-rw-r--r--src/network/ssl/qsslconfiguration.h5
-rw-r--r--src/network/ssl/qsslsocket_schannel.cpp3
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp1
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm1
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp1
-rw-r--r--src/platformsupport/services/genericunix/qgenericunixservices.cpp7
-rw-r--r--src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp10
-rw-r--r--src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h3
-rw-r--r--src/platformsupport/windowsuiautomation/uiatypes_p.h16
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm1
-rw-r--r--src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp26
-rw-r--r--src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp10
-rw-r--r--src/plugins/sqldrivers/odbc/qsql_odbc.cpp2
-rw-r--r--src/plugins/styles/mac/qmacstyle_mac.mm1
-rw-r--r--src/printsupport/dialogs/qprintdialog_mac.mm72
-rw-r--r--src/tools/androiddeployqt/main.cpp16
-rw-r--r--src/widgets/graphicsview/qgraphicsscene.cpp1
-rw-r--r--src/widgets/graphicsview/qgraphicssceneindex.cpp1
-rw-r--r--src/widgets/graphicsview/qgraphicsview.cpp1
-rw-r--r--src/widgets/graphicsview/qgraphicswidget.cpp1
-rw-r--r--src/widgets/styles/qcommonstyle.cpp2
-rw-r--r--src/widgets/styles/qfusionstyle.cpp1
-rw-r--r--src/widgets/styles/qstylesheetstyle.cpp1
-rw-r--r--src/widgets/styles/qwindowsstyle.cpp1
-rw-r--r--tests/auto/corelib/io/qloggingregistry/tst_qloggingregistry.cpp7
-rw-r--r--tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp7
-rw-r--r--tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp285
-rw-r--r--tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp1148
-rw-r--r--tests/auto/gui/painting/qpainter/tst_qpainter.cpp1
-rw-r--r--tests/auto/gui/painting/qregion/tst_qregion.cpp1
-rw-r--r--tests/auto/gui/painting/qtransform/tst_qtransform.cpp4
-rw-r--r--tests/auto/gui/qopengl/tst_qopengl.cpp1
-rw-r--r--tests/auto/gui/rhi/qrhi/data/buildshaders.bat1
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simple.frag.qsbbin730 -> 740 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simple.vert.qsbbin791 -> 786 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsbbin1208 -> 1206 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsbbin964 -> 983 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag17
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag.qsbbin0 -> 1693 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/data/textured.frag.qsbbin1574 -> 1590 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/data/textured.vert.qsbbin1342 -> 1368 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/tst_qrhi.cpp143
-rw-r--r--tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp170
-rw-r--r--tests/auto/opengl/qgl/tst_qgl.cpp2525
-rw-r--r--tests/auto/other/lancelot/paintcommands.cpp1
-rw-r--r--tests/auto/testlib/selftests/expected_pass.junitxml14
-rw-r--r--tests/auto/testlib/selftests/expected_pass.lightxml26
-rw-r--r--tests/auto/testlib/selftests/expected_pass.tap11
-rw-r--r--tests/auto/testlib/selftests/expected_pass.teamcity12
-rw-r--r--tests/auto/testlib/selftests/expected_pass.txt9
-rw-r--r--tests/auto/testlib/selftests/expected_pass.xml29
-rw-r--r--tests/auto/testlib/selftests/pass/pass.pro9
-rw-r--r--tests/auto/testlib/selftests/pass/tst_pass.cpp56
-rw-r--r--tests/auto/testlib/selftests/selftests.pri1
-rw-r--r--tests/auto/testlib/selftests/tst_selftests.cpp5
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp1
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicspixmapitem/tst_qgraphicspixmapitem.cpp1
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicspolygonitem/tst_qgraphicspolygonitem.cpp1
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp1
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp1
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview_2.cpp1
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp1
-rw-r--r--tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp1
-rw-r--r--tests/benchmarks/gui/painting/qtbench/benchmarktests.h1
-rw-r--r--tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp1
131 files changed, 6180 insertions, 1213 deletions
diff --git a/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp b/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp
index 822791533b..420fd6186a 100644
--- a/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp
+++ b/examples/corelib/threads/mandelbrot/mandelbrotwidget.cpp
@@ -56,29 +56,28 @@
#include <math.h>
//! [0]
-const double DefaultCenterX = -0.637011f;
-const double DefaultCenterY = -0.0395159f;
-const double DefaultScale = 0.00403897f;
+const double DefaultCenterX = -0.637011;
+const double DefaultCenterY = -0.0395159;
+const double DefaultScale = 0.00403897;
-const double ZoomInFactor = 0.8f;
+const double ZoomInFactor = 0.8;
const double ZoomOutFactor = 1 / ZoomInFactor;
const int ScrollStep = 20;
//! [0]
//! [1]
-MandelbrotWidget::MandelbrotWidget(QWidget *parent)
- : QWidget(parent)
+MandelbrotWidget::MandelbrotWidget(QWidget *parent) :
+ QWidget(parent),
+ centerX(DefaultCenterX),
+ centerY(DefaultCenterY),
+ pixmapScale(DefaultScale),
+ curScale(DefaultScale)
{
- centerX = DefaultCenterX;
- centerY = DefaultCenterY;
- pixmapScale = DefaultScale;
- curScale = DefaultScale;
-
connect(&thread, &RenderThread::renderedImage,
this, &MandelbrotWidget::updatePixmap);
setWindowTitle(tr("Mandelbrot"));
-#ifndef QT_NO_CURSOR
+#if QT_CONFIG(cursor)
setCursor(Qt::CrossCursor);
#endif
resize(550, 400);
@@ -102,7 +101,7 @@ void MandelbrotWidget::paintEvent(QPaintEvent * /* event */)
//! [4]
//! [5]
- if (curScale == pixmapScale) {
+ if (qFuzzyCompare(curScale, pixmapScale)) {
//! [5] //! [6]
painter.drawPixmap(pixmapOffset, pixmap);
//! [6] //! [7]
@@ -176,8 +175,8 @@ void MandelbrotWidget::keyPressEvent(QKeyEvent *event)
//! [12]
void MandelbrotWidget::wheelEvent(QWheelEvent *event)
{
- int numDegrees = event->angleDelta().y() / 8;
- double numSteps = numDegrees / 15.0f;
+ const int numDegrees = event->angleDelta().y() / 8;
+ const double numSteps = numDegrees / double(15);
zoom(pow(ZoomInFactor, numSteps));
}
//! [12]
diff --git a/examples/corelib/threads/mandelbrot/renderthread.cpp b/examples/corelib/threads/mandelbrot/renderthread.cpp
index eee44c7242..22ce81c32d 100644
--- a/examples/corelib/threads/mandelbrot/renderthread.cpp
+++ b/examples/corelib/threads/mandelbrot/renderthread.cpp
@@ -57,9 +57,6 @@
RenderThread::RenderThread(QObject *parent)
: QThread(parent)
{
- restart = false;
- abort = false;
-
for (int i = 0; i < ColormapSize; ++i)
colormap[i] = rgbFromWaveLength(380.0 + (i * 400.0 / ColormapSize));
}
@@ -102,10 +99,10 @@ void RenderThread::run()
{
forever {
mutex.lock();
- QSize resultSize = this->resultSize;
- double scaleFactor = this->scaleFactor;
- double centerX = this->centerX;
- double centerY = this->centerY;
+ const QSize resultSize = this->resultSize;
+ const double scaleFactor = this->scaleFactor;
+ const double centerX = this->centerX;
+ const double centerY = this->centerY;
mutex.unlock();
//! [3]
@@ -128,20 +125,20 @@ void RenderThread::run()
if (abort)
return;
- uint *scanLine =
+ auto scanLine =
reinterpret_cast<uint *>(image.scanLine(y + halfHeight));
- double ay = centerY + (y * scaleFactor);
+ const double ay = centerY + (y * scaleFactor);
for (int x = -halfWidth; x < halfWidth; ++x) {
- double ax = centerX + (x * scaleFactor);
+ const double ax = centerX + (x * scaleFactor);
double a1 = ax;
double b1 = ay;
int numIterations = 0;
do {
++numIterations;
- double a2 = (a1 * a1) - (b1 * b1) + ax;
- double b2 = (2 * a1 * b1) + ay;
+ const double a2 = (a1 * a1) - (b1 * b1) + ax;
+ const double b2 = (2 * a1 * b1) + ay;
if ((a2 * a2) + (b2 * b2) > Limit)
break;
@@ -187,9 +184,9 @@ void RenderThread::run()
//! [10]
uint RenderThread::rgbFromWaveLength(double wave)
{
- double r = 0.0;
- double g = 0.0;
- double b = 0.0;
+ double r = 0;
+ double g = 0;
+ double b = 0;
if (wave >= 380.0 && wave <= 440.0) {
r = -1.0 * (wave - 440.0) / (440.0 - 380.0);
diff --git a/examples/corelib/threads/mandelbrot/renderthread.h b/examples/corelib/threads/mandelbrot/renderthread.h
index 4f0394d554..934cc17d74 100644
--- a/examples/corelib/threads/mandelbrot/renderthread.h
+++ b/examples/corelib/threads/mandelbrot/renderthread.h
@@ -78,7 +78,7 @@ protected:
void run() override;
private:
- uint rgbFromWaveLength(double wave);
+ static uint rgbFromWaveLength(double wave);
QMutex mutex;
QWaitCondition condition;
@@ -86,8 +86,8 @@ private:
double centerY;
double scaleFactor;
QSize resultSize;
- bool restart;
- bool abort;
+ bool restart = false;
+ bool abort = false;
enum { ColormapSize = 512 };
uint colormap[ColormapSize];
diff --git a/examples/opengl/paintedwindow/paintedwindow.cpp b/examples/opengl/paintedwindow/paintedwindow.cpp
index 799431a765..94aa215288 100644
--- a/examples/opengl/paintedwindow/paintedwindow.cpp
+++ b/examples/opengl/paintedwindow/paintedwindow.cpp
@@ -54,6 +54,7 @@
#include <QOpenGLContext>
#include <QOpenGLPaintDevice>
#include <QPainter>
+#include <QPainterPath>
#include <QScreen>
#include <QTimer>
diff --git a/examples/opengl/qopenglwindow/main.cpp b/examples/opengl/qopenglwindow/main.cpp
index 8932269ddf..7ce4dd0977 100644
--- a/examples/opengl/qopenglwindow/main.cpp
+++ b/examples/opengl/qopenglwindow/main.cpp
@@ -51,6 +51,7 @@
#include <QOpenGLWindow>
#include <QScreen>
#include <QPainter>
+#include <QPainterPath>
#include <QGuiApplication>
#include <QMatrix4x4>
#include <QStaticText>
diff --git a/examples/qpa/qrasterwindow/main.cpp b/examples/qpa/qrasterwindow/main.cpp
index 958da2205a..699c950c27 100644
--- a/examples/qpa/qrasterwindow/main.cpp
+++ b/examples/qpa/qrasterwindow/main.cpp
@@ -50,6 +50,7 @@
#include <QRasterWindow>
#include <QPainter>
+#include <QPainterPath>
#include <QGuiApplication>
#include <QMatrix4x4>
#include <QTimer>
diff --git a/examples/sql/doc/src/drilldown.qdoc b/examples/sql/doc/src/drilldown.qdoc
index 8beb515a83..a7a9601c26 100644
--- a/examples/sql/doc/src/drilldown.qdoc
+++ b/examples/sql/doc/src/drilldown.qdoc
@@ -437,6 +437,9 @@
\snippet drilldown/imageitem.h 0
+ We declare a \c Type enum value for our custom item and reimplement
+ \l{QGreaphicsItem::}{type()}. This is done so we can safely use
+ qgraphicsitem_cast().
In addition, we implement a public \c id() function to be able to
identify the associated location and a public \c adjust() function
that can be called to ensure that the image item is given the
diff --git a/examples/sql/drilldown/imageitem.h b/examples/sql/drilldown/imageitem.h
index abb9103c7e..324c847b12 100644
--- a/examples/sql/drilldown/imageitem.h
+++ b/examples/sql/drilldown/imageitem.h
@@ -60,8 +60,11 @@ class ImageItem : public QObject, public QGraphicsPixmapItem
Q_OBJECT
public:
+ enum { Type = UserType + 1 };
+
ImageItem(int id, const QPixmap &pixmap, QGraphicsItem *parent = nullptr);
+ int type() const override { return Type; }
void adjust();
int id() const;
diff --git a/examples/widgets/painting/basicdrawing/renderarea.cpp b/examples/widgets/painting/basicdrawing/renderarea.cpp
index a1437dea8f..09d610ee95 100644
--- a/examples/widgets/painting/basicdrawing/renderarea.cpp
+++ b/examples/widgets/painting/basicdrawing/renderarea.cpp
@@ -51,6 +51,7 @@
#include "renderarea.h"
#include <QPainter>
+#include <QPainterPath>
//! [0]
RenderArea::RenderArea(QWidget *parent)
diff --git a/examples/widgets/widgets/styles/norwegianwoodstyle.cpp b/examples/widgets/widgets/styles/norwegianwoodstyle.cpp
index 31150cd994..34a63e0eea 100644
--- a/examples/widgets/widgets/styles/norwegianwoodstyle.cpp
+++ b/examples/widgets/widgets/styles/norwegianwoodstyle.cpp
@@ -52,6 +52,7 @@
#include <QComboBox>
#include <QPainter>
+#include <QPainterPath>
#include <QPushButton>
#include <QStyleFactory>
diff --git a/mkspecs/android-clang/qmake.conf b/mkspecs/android-clang/qmake.conf
index 31ee5d2637..5cc5a20f71 100644
--- a/mkspecs/android-clang/qmake.conf
+++ b/mkspecs/android-clang/qmake.conf
@@ -43,6 +43,9 @@ isEmpty(ALL_ANDROID_ABIS): ALL_ANDROID_ABIS = arm64-v8a armeabi-v7a x86_64 x86
CONFIG += $$ANDROID_PLATFORM
+ANDROID_MIN_SDK_VERSION = $$replace(ANDROID_PLATFORM, "android-", "")
+ANDROID_TARGET_SDK_VERSION = 28
+
NDK_LLVM_PATH = $$NDK_ROOT/toolchains/llvm/prebuilt/$$NDK_HOST
QMAKE_CC = $$NDK_LLVM_PATH/bin/clang
QMAKE_CXX = $$NDK_LLVM_PATH/bin/clang++
diff --git a/mkspecs/features/android/android_deployment_settings.prf b/mkspecs/features/android/android_deployment_settings.prf
index f375a687a9..7cda5096b1 100644
--- a/mkspecs/features/android/android_deployment_settings.prf
+++ b/mkspecs/features/android/android_deployment_settings.prf
@@ -53,6 +53,12 @@ contains(TEMPLATE, ".*app"):!build_pass:!android-embedded {
!isEmpty(ANDROID_VERSION_CODE): \
FILE_CONTENT += " \"android-version-code\": $$emitString($$ANDROID_VERSION_CODE),"
+ !isEmpty(ANDROID_MIN_SDK_VERSION): \
+ FILE_CONTENT += " \"android-min-sdk-version\": $$emitString($$ANDROID_MIN_SDK_VERSION),"
+
+ !isEmpty(ANDROID_TARGET_SDK_VERSION): \
+ FILE_CONTENT += " \"android-target-sdk-version\": $$emitString($$ANDROID_TARGET_SDK_VERSION),"
+
!isEmpty(ANDROID_EXTRA_LIBS): \
FILE_CONTENT += " \"android-extra-libs\": $$emitString($$join(ANDROID_EXTRA_LIBS, ",")),"
diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc
index 1e1e23495c..351009bd1c 100644
--- a/qmake/doc/src/qmake-manual.qdoc
+++ b/qmake/doc/src/qmake-manual.qdoc
@@ -1111,6 +1111,15 @@
\row \li designer \li The target is a plugin for \QD.
\row \li no_lflags_merge \li Ensures that the list of libraries stored in the
\c LIBS variable is not reduced to a list of unique values before it is used.
+ \row \li metatypes \li Create a \c {<name>_metatypes.json} file for the
+ current project. \c {<name>} is the all lowercase base name of
+ \l TARGET.
+ \row \li qmltypes \li Automatically register QML types defined in C++.
+ For more information, see \l {Defining QML Types from C++}.
+ Also, create a \c {<template>.qmltypes} file for the current
+ project. \c <template> will be \c plugins (plural, for historical
+ reasons) if \c plugin is set, or the value of \l TEMPLATE otherwise.
+ \c qmltypes implies \c metatypes.
\endtable
These options define specific features on Windows only:
@@ -2579,6 +2588,32 @@
For more information, see \l {Expressing Supported iOS Versions}.
+ \section1 QML_IMPORT_MAJOR_VERSION
+
+ Specifies the major version to be used for automatically generated QML type
+ registrations. For more information, see \l {Defining QML Types from C++}.
+
+ \section1 QML_IMPORT_MINOR_VERSION
+
+ When automatically registering QML types defined in C++, register an
+ additional version of the module using this minor version. Generally,
+ minor versions to be registered are inferred from the meta objects.
+
+ You can use this variable if the meta objects have not changed and you
+ still want to import a QML module with a newer minor version number. For
+ example, \c MyModule metaobjects are at \c 1.1 level, but you want to import
+ the module as \c 1.3.
+
+ \section1 QML_IMPORT_VERSION
+
+ Specifies \l QML_IMPORT_MAJOR_VERSION and \l QML_IMPORT_MINOR_VERSION as a
+ \c {<major>.<minor>} version string.
+
+ \section1 QML_IMPORT_NAME
+
+ Specifies the module name to be used for automatically generated QML type
+ registrations. For more information, see \l {Defining QML Types from C++}.
+
\section1 QT
Specifies the \l{All Modules}{Qt modules} that are used by your project. For
diff --git a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
index 4b7e1f3d38..5028f28f8e 100644
--- a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
+++ b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml
index 8dadd1eac8..e31dea6a8c 100644
--- a/src/android/templates/AndroidManifest.xml
+++ b/src/android/templates/AndroidManifest.xml
@@ -1,7 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<manifest package="org.qtproject.example" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="-- %%INSERT_VERSION_NAME%% --" android:versionCode="-- %%INSERT_VERSION_CODE%% --" android:installLocation="auto">
- <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="28"/>
-
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
Remove the comment if you do not require these default permissions. -->
<!-- %%INSERT_PERMISSIONS -->
diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle
index 3087d08c83..d5b3b93499 100644
--- a/src/android/templates/build.gradle
+++ b/src/android/templates/build.gradle
@@ -5,7 +5,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath 'com.android.tools.build:gradle:3.6.0'
}
}
@@ -59,4 +59,10 @@ android {
aaptOptions {
noCompress 'rcc'
}
+
+ defaultConfig {
+ resConfig "en"
+ minSdkVersion = qtMinSdkVersion
+ targetSdkVersion = qtTargetSdkVersion
+ }
}
diff --git a/src/corelib/Qt5AndroidSupport.cmake b/src/corelib/Qt5AndroidSupport.cmake
index 5f24fb0e8c..4db38f3957 100644
--- a/src/corelib/Qt5AndroidSupport.cmake
+++ b/src/corelib/Qt5AndroidSupport.cmake
@@ -18,6 +18,8 @@ if (NOT ${PROJECT_NAME}-MultiAbiBuild)
option(ANDROID_BUILD_ABI_${abi} "Enable the build for Android ${abi}" ${abi_initial_value})
endif()
endforeach()
+ option(ANDROID_MIN_SDK_VERSION "Android minimum SDK version" "21")
+ option(ANDROID_TARGET_SDK_VERSION "Android target SDK version" "28")
# Make sure to delete the "android-build" directory, which contains all the
# build artefacts, and also the androiddeployqt/gradle artefacts
@@ -101,6 +103,9 @@ if (NOT ${PROJECT_NAME}-MultiAbiBuild)
generate_json_variable(ANDROID_VERSION_NAME "android-version-name")
generate_json_variable_list(ANDROID_EXTRA_LIBS "android-extra-libs")
generate_json_variable_list(QML_IMPORT_PATH "qml-import-paths")
+ generate_json_variable_list(ANDROID_MIN_SDK_VERSION "android-min-sdk-version")
+ generate_json_variable_list(ANDROID_TARGET_SDK_VERSION "android-target-sdk-version")
+
configure_file(
"${CMAKE_BINARY_DIR}/android_deployment_settings.json.in"
diff --git a/src/corelib/doc/src/dontdocument.qdoc b/src/corelib/doc/src/dontdocument.qdoc
index b1af82fbe2..c84b789c46 100644
--- a/src/corelib/doc/src/dontdocument.qdoc
+++ b/src/corelib/doc/src/dontdocument.qdoc
@@ -34,7 +34,7 @@
QMetaTypeId2 QObjectData QObjectUserData QMapNodeBase QMapNode QMapDataBase
QMapData QHashData QHashNode QArrayDataPointer QTextStreamManipulator
QContiguousCacheData QContiguousCacheTypedData QNoDebug QUrlTwoFlags
- QCborValueRef qfloat16 QDeferredDeleteEvent QSpecialInteger QLittleEndianStorageType
+ QCborValueRef QDeferredDeleteEvent QSpecialInteger QLittleEndianStorageType
QBigEndianStorageType QFactoryInterface QFutureWatcherBase QJsonValuePtr
QJsonValueRefPtr QAbstractConcatenable QStringBuilderCommon
QTextCodec::ConverterState QThreadStorageData QTextStreamManipulator)
diff --git a/src/corelib/doc/src/resource-system.qdoc b/src/corelib/doc/src/resource-system.qdoc
index f9ef317799..6ff10804f5 100644
--- a/src/corelib/doc/src/resource-system.qdoc
+++ b/src/corelib/doc/src/resource-system.qdoc
@@ -179,6 +179,17 @@
rcc -compress 2 -compress-algo zlib myresources.qrc
\endcode
+ It is also possible to use \c threshold, \c compress, and \c compress-algo
+ as attributes in a .qrc \c file tag.
+
+ \code
+ <qresource>
+ <file compress="1" compress-algo="zstd">data.txt</file>
+ </qresource>
+ \endcode
+
+ The above will select the \c zstd algorithm with compression level 1.
+
\c rcc supports the following compression algorithms and compression
levels:
@@ -196,10 +207,10 @@
library to choose an implementation-defined default.
\li \c{zlib}: use the \l{https://zlib.net}{zlib} library to compress
- contents. Valid compression levels range from 1 to 9, with 1the least
- compression (least CPU time) and 9 the most compression (most CPU time).
- The special value 0 means "no compression" and should not be used. The
- default is implementation-defined, but usually is level 6.
+ contents. Valid compression levels range from 1 to 9, with 1 applying
+ the least compression (least CPU time) and 9 the most compression (most
+ CPU time). The special value 0 means "no compression" and should not be
+ used. The default is implementation-defined, but usually is level 6.
\li \c{none}: no compression. This is the same as the \c{-no-compress}
option.
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
index 3d82bbe95a..1f06b10313 100644
--- a/src/corelib/global/qfloat16.cpp
+++ b/src/corelib/global/qfloat16.cpp
@@ -45,18 +45,20 @@
QT_BEGIN_NAMESPACE
/*!
- \headerfile <QFloat16>
- \title 16-bit Floating Point Support
+ \class qfloat16
+ \keyword 16-bit Floating Point Support
\ingroup funclists
- \brief The <QFloat16> header file provides 16-bit floating point support.
-
- This header file provides support for half-precision (16-bit) floating
- point data with the class \c qfloat16. It is fully compliant with IEEE
- 754 as a storage type. This implies that any arithmetic operation on a
- \c qfloat16 instance results in the value first being converted to a
- \c float. This conversion to and from \c float is performed by hardware
- when possible, but on processors that do not natively support half-precision,
- the conversion is performed through a sequence of lookup table operations.
+ \inmodule QtCore
+ \inheaderfile QFloat16
+ \brief Provides 16-bit floating point support.
+
+ The \c qfloat16 class provides support for half-precision (16-bit) floating
+ point data. It is fully compliant with IEEE 754 as a storage type. This
+ implies that any arithmetic operation on a \c qfloat16 instance results in
+ the value first being converted to a \c float. This conversion to and from
+ \c float is performed by hardware when possible, but on processors that do
+ not natively support half-precision, the conversion is performed through a
+ sequence of lookup table operations.
\c qfloat16 should be treated as if it were a POD (plain old data) type.
Consequently, none of the supported operations need any elaboration beyond
@@ -68,7 +70,7 @@ QT_BEGIN_NAMESPACE
/*!
\macro QT_NO_FLOAT16_OPERATORS
- \relates <QFloat16>
+ \relates qfloat16
\since 5.12.4
Defining this macro disables the arithmetic operators for qfloat16.
@@ -81,7 +83,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn bool qIsInf(qfloat16 f)
- \relates <QFloat16>
+ \relates qfloat16
Returns true if the \c qfloat16 \a {f} is equivalent to infinity.
@@ -90,7 +92,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn bool qIsNaN(qfloat16 f)
- \relates <QFloat16>
+ \relates qfloat16
Returns true if the \c qfloat16 \a {f} is not a number (NaN).
@@ -99,7 +101,7 @@ QT_BEGIN_NAMESPACE
/*!
\fn bool qIsFinite(qfloat16 f)
- \relates <QFloat16>
+ \relates qfloat16
Returns true if the \c qfloat16 \a {f} is a finite number.
@@ -130,7 +132,7 @@ QT_BEGIN_NAMESPACE
\since 5.14
\fn bool qfloat16::isNormal() const noexcept
- Tests whether this \c qfloat16 value is finite and in normal form.
+ Returns \c true if this \c qfloat16 value is finite and in normal form.
\sa qFpClassify()
*/
@@ -167,7 +169,7 @@ int qfloat16::fpClassify() const noexcept
}
/*! \fn int qRound(qfloat16 value)
- \relates <QFloat16>
+ \relates qfloat16
Rounds \a value to the nearest integer.
@@ -175,7 +177,7 @@ int qfloat16::fpClassify() const noexcept
*/
/*! \fn qint64 qRound64(qfloat16 value)
- \relates <QFloat16>
+ \relates qfloat16
Rounds \a value to the nearest 64-bit integer.
@@ -183,7 +185,7 @@ int qfloat16::fpClassify() const noexcept
*/
/*! \fn bool qFuzzyCompare(qfloat16 p1, qfloat16 p2)
- \relates <QFloat16>
+ \relates qfloat16
Compares the floating point value \a p1 and \a p2 and
returns \c true if they are considered equal, otherwise \c false.
@@ -256,7 +258,7 @@ static void qFloatFromFloat16_fast(float *, const quint16 *, qsizetype) noexcept
#endif
/*!
\since 5.11
- \relates <QFloat16>
+ \relates qfloat16
Converts \a len floats from \a in to qfloat16 and stores them in \a out.
Both \a in and \a out must have \a len allocated entries.
@@ -272,7 +274,7 @@ Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *out, const float *in, qsizetype len
/*!
\since 5.11
- \relates <QFloat16>
+ \relates qfloat16
Converts \a len qfloat16 from \a in to floats and stores them in \a out.
Both \a in and \a out must have \a len allocated entries.
diff --git a/src/corelib/io/qloggingregistry.cpp b/src/corelib/io/qloggingregistry.cpp
index e8eb18b4c1..cacebfbda6 100644
--- a/src/corelib/io/qloggingregistry.cpp
+++ b/src/corelib/io/qloggingregistry.cpp
@@ -75,7 +75,7 @@ QLoggingRule::QLoggingRule() :
\internal
Constructs a logging rule.
*/
-QLoggingRule::QLoggingRule(const QStringRef &pattern, bool enabled) :
+QLoggingRule::QLoggingRule(QStringView pattern, bool enabled) :
messageType(-1),
enabled(enabled)
{
@@ -87,7 +87,7 @@ QLoggingRule::QLoggingRule(const QStringRef &pattern, bool enabled) :
Return value 1 means filter passed, 0 means filter doesn't influence this
category, -1 means category doesn't pass this filter.
*/
-int QLoggingRule::pass(const QString &cat, QtMsgType msgType) const
+int QLoggingRule::pass(QLatin1String cat, QtMsgType msgType) const
{
// check message type
if (messageType > -1 && messageType != msgType)
@@ -113,7 +113,7 @@ int QLoggingRule::pass(const QString &cat, QtMsgType msgType) const
return (enabled ? 1 : -1);
} else if (flags == RightFilter) {
// matches right
- if (idx == (cat.count() - category.count()))
+ if (idx == (cat.size() - category.count()))
return (enabled ? 1 : -1);
}
}
@@ -129,26 +129,22 @@ int QLoggingRule::pass(const QString &cat, QtMsgType msgType) const
*.io.warning RightFilter, QtWarningMsg
*.core.* MidFilter
*/
-void QLoggingRule::parse(const QStringRef &pattern)
+void QLoggingRule::parse(QStringView pattern)
{
- QStringRef p;
+ QStringView p;
// strip trailing ".messagetype"
if (pattern.endsWith(QLatin1String(".debug"))) {
- p = QStringRef(pattern.string(), pattern.position(),
- pattern.length() - 6); // strlen(".debug")
+ p = pattern.chopped(6); // strlen(".debug")
messageType = QtDebugMsg;
} else if (pattern.endsWith(QLatin1String(".info"))) {
- p = QStringRef(pattern.string(), pattern.position(),
- pattern.length() - 5); // strlen(".info")
+ p = pattern.chopped(5); // strlen(".info")
messageType = QtInfoMsg;
} else if (pattern.endsWith(QLatin1String(".warning"))) {
- p = QStringRef(pattern.string(), pattern.position(),
- pattern.length() - 8); // strlen(".warning")
+ p = pattern.chopped(8); // strlen(".warning")
messageType = QtWarningMsg;
} else if (pattern.endsWith(QLatin1String(".critical"))) {
- p = QStringRef(pattern.string(), pattern.position(),
- pattern.length() - 9); // strlen(".critical")
+ p = pattern.chopped(9); // strlen(".critical")
messageType = QtCriticalMsg;
} else {
p = pattern;
@@ -159,11 +155,11 @@ void QLoggingRule::parse(const QStringRef &pattern)
} else {
if (p.endsWith(QLatin1Char('*'))) {
flags |= LeftFilter;
- p = QStringRef(p.string(), p.position(), p.length() - 1);
+ p = p.chopped(1);
}
if (p.startsWith(QLatin1Char('*'))) {
flags |= RightFilter;
- p = QStringRef(p.string(), p.position() + 1, p.length() - 1);
+ p = p.mid(1);
}
if (p.contains(QLatin1Char('*'))) // '*' only supported at start/end
flags = PatternFlags();
@@ -208,7 +204,7 @@ void QLoggingSettingsParser::setContent(QTextStream &stream)
_rules.clear();
QString line;
while (stream.readLineInto(&line))
- parseNextLine(QStringRef(&line));
+ parseNextLine(qToStringViewIgnoringNull(line));
}
/*!
@@ -216,7 +212,7 @@ void QLoggingSettingsParser::setContent(QTextStream &stream)
Parses one line of the configuation file
*/
-void QLoggingSettingsParser::parseNextLine(QStringRef line)
+void QLoggingSettingsParser::parseNextLine(QStringView line)
{
// Remove whitespace at start and end of line:
line = line.trimmed();
@@ -227,7 +223,7 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line)
if (line.startsWith(QLatin1Char('[')) && line.endsWith(QLatin1Char(']'))) {
// new section
- auto sectionName = line.mid(1, line.size() - 2).trimmed();
+ auto sectionName = line.mid(1).chopped(1).trimmed();
m_inRulesSection = sectionName.compare(QLatin1String("rules"), Qt::CaseInsensitive) == 0;
return;
}
@@ -240,9 +236,9 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line)
#if QT_CONFIG(settings)
QString tmp;
QSettingsPrivate::iniUnescapedKey(key.toUtf8(), 0, key.length(), tmp);
- QStringRef pattern = QStringRef(&tmp, 0, tmp.length());
+ QStringView pattern = qToStringViewIgnoringNull(tmp);
#else
- QStringRef pattern = key;
+ QStringView pattern = key;
#endif
const auto valueStr = line.mid(equalPos + 1).trimmed();
int value = -1;
@@ -252,7 +248,7 @@ void QLoggingSettingsParser::parseNextLine(QStringRef line)
value = 0;
QLoggingRule rule(pattern, (value == 1));
if (rule.flags != 0 && (value != -1))
- _rules.append(rule);
+ _rules.append(std::move(rule));
else
warnMsg("Ignoring malformed logging rule: '%s'", line.toUtf8().constData());
} else {
@@ -460,7 +456,7 @@ void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
debug = false;
}
- QString categoryName = QLatin1String(cat->categoryName());
+ const auto categoryName = QLatin1String(cat->categoryName());
for (const auto &ruleSet : reg->ruleSets) {
for (const auto &rule : ruleSet) {
diff --git a/src/corelib/io/qloggingregistry_p.h b/src/corelib/io/qloggingregistry_p.h
index 12a1f166b3..3ac429b147 100644
--- a/src/corelib/io/qloggingregistry_p.h
+++ b/src/corelib/io/qloggingregistry_p.h
@@ -67,8 +67,8 @@ class Q_AUTOTEST_EXPORT QLoggingRule
{
public:
QLoggingRule();
- QLoggingRule(const QStringRef &pattern, bool enabled);
- int pass(const QString &categoryName, QtMsgType type) const;
+ QLoggingRule(QStringView pattern, bool enabled);
+ int pass(QLatin1String categoryName, QtMsgType type) const;
enum PatternFlag {
FullText = 0x1,
@@ -84,7 +84,7 @@ public:
bool enabled;
private:
- void parse(const QStringRef &pattern);
+ void parse(QStringView pattern);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QLoggingRule::PatternFlags)
@@ -101,7 +101,7 @@ public:
QVector<QLoggingRule> rules() const { return _rules; }
private:
- void parseNextLine(QStringRef line);
+ void parseNextLine(QStringView line);
private:
bool m_inRulesSection = false;
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 3b708d7727..1f4be24913 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -2475,12 +2475,11 @@ int QProcess::execute(const QString &program, const QStringList &arguments)
*/
int QProcess::execute(const QString &command)
{
- QProcess process;
- process.setProcessChannelMode(ForwardedChannels);
- process.start(command);
- if (!process.waitForFinished(-1) || process.error() == FailedToStart)
+ QStringList args = splitCommand(command);
+ if (args.isEmpty())
return -2;
- return process.exitStatus() == QProcess::NormalExit ? process.exitCode() : -1;
+ QString program = args.takeFirst();
+ return execute(program, args);
}
/*!
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index e636712e57..9a2fd196a2 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -732,7 +732,7 @@ const uchar *QResource::data() const
\note If the data was compressed, this function will decompress every time
it is called. The result is not cached between calls.
- \sa uncompressedData(), size(), isCompressed(), isFile()
+ \sa uncompressedSize(), size(), isCompressed(), isFile()
*/
QByteArray QResource::uncompressedData() const
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 4d9f3b01de..ea0016c5af 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -337,7 +337,7 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
\value QPolygon QPolygon
\value QPolygonF QPolygonF
\value QColor QColor
- \value QColorSpace QColorSpace
+ \value QColorSpace QColorSpace (introduced in Qt 5.15)
\value QSizeF QSizeF
\value QRectF QRectF
\value QLine QLine
@@ -383,7 +383,7 @@ Q_GLOBAL_STATIC(QMetaTypeCustomRegistry, customTypeRegistry)
\value QCborMap QCborMap
\value QCborSimpleType QCborSimpleType
\value QModelIndex QModelIndex
- \value QPersistentModelIndex QPersistentModelIndex (since 5.5)
+ \value QPersistentModelIndex QPersistentModelIndex (introduced in Qt 5.5)
\value QUuid QUuid
\value QByteArrayList QByteArrayList
diff --git a/src/corelib/mimetypes/mimetypes.pri b/src/corelib/mimetypes/mimetypes.pri
index 8cbe7b69ae..288ccf063e 100644
--- a/src/corelib/mimetypes/mimetypes.pri
+++ b/src/corelib/mimetypes/mimetypes.pri
@@ -26,9 +26,12 @@ qtConfig(mimetype) {
qtConfig(mimetype-database) {
outpath = .rcc
+ android {
+ outpath = $$outpath/$${QT_ARCH}
+ }
debug_and_release {
- CONFIG(debug, debug|release): outpath = .rcc/debug
- else: outpath = .rcc/release
+ CONFIG(debug, debug|release): outpath = $$outpath/debug
+ else: outpath = $$outpath/release
}
mimedb.depends = $$PWD/mime/generate.pl
diff --git a/src/corelib/text/qbytearray.h b/src/corelib/text/qbytearray.h
index e3fec1e62c..d260a9d678 100644
--- a/src/corelib/text/qbytearray.h
+++ b/src/corelib/text/qbytearray.h
@@ -219,8 +219,8 @@ public:
int count(const char *a) const;
int count(const QByteArray &a) const;
- inline int compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
- inline int compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+ inline int compare(const char *c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
+ inline int compare(const QByteArray &a, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
Q_REQUIRED_RESULT QByteArray left(int len) const;
Q_REQUIRED_RESULT QByteArray right(int len) const;
@@ -555,12 +555,12 @@ inline bool QByteArray::contains(const QByteArray &a) const
{ return indexOf(a) != -1; }
inline bool QByteArray::contains(char c) const
{ return indexOf(c) != -1; }
-inline int QByteArray::compare(const char *c, Qt::CaseSensitivity cs) const
+inline int QByteArray::compare(const char *c, Qt::CaseSensitivity cs) const noexcept
{
return cs == Qt::CaseSensitive ? qstrcmp(*this, c) :
qstrnicmp(data(), size(), c, -1);
}
-inline int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs) const
+inline int QByteArray::compare(const QByteArray &a, Qt::CaseSensitivity cs) const noexcept
{
return cs == Qt::CaseSensitive ? qstrcmp(*this, a) :
qstrnicmp(data(), size(), a.data(), a.size());
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 757f248e8a..745d3d8047 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -6154,6 +6154,16 @@ QString& QString::fill(QChar ch, int size)
sensitivity setting \a cs.
*/
+/*!
+ \fn int QString::compare(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+
+ \since 5.14
+ \overload compare()
+
+ Performs a comparison of this with \a ch, using the case
+ sensitivity setting \a cs.
+*/
+
#if QT_STRINGVIEW_LEVEL < 2
/*!
\overload compare()
@@ -9576,6 +9586,23 @@ QString &QString::setRawData(const QChar *unicode, int size)
*/
/*!
+ \fn int QLatin1String::compare(QStringView str, Qt::CaseSensitivity cs) const
+ \fn int QLatin1String::compare(QLatin1String l1, Qt::CaseSensitivity cs) const
+ \fn int QLatin1String::compare(QChar ch) const
+ \fn int QLatin1String::compare(QChar ch, Qt::CaseSensitivity cs) const
+ \since 5.14
+
+ Returns an integer that compares to zero as this Latin-1 string compares to the
+ string-view \a str, Latin-1 string \a l1, or character \a ch, respectively.
+
+ If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive;
+ otherwise the comparison is case-insensitive.
+
+ \sa operator==(), operator<(), operator>()
+*/
+
+
+/*!
\fn bool QLatin1String::startsWith(QStringView str, Qt::CaseSensitivity cs) const
\since 5.10
\fn bool QLatin1String::startsWith(QLatin1String l1, Qt::CaseSensitivity cs) const
@@ -10943,6 +10970,19 @@ QStringRef QStringRef::appendTo(QString *string) const
/*!
\overload
+ \fn int QStringRef::compare(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ \since 5.14
+
+ Compares this string with \a ch and returns an
+ integer less than, equal to, or greater than zero if this string
+ is less than, equal to, or greater than \a ch, interpreted as a string of length one.
+
+ If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
+ otherwise the comparison is case insensitive.
+*/
+
+/*!
+ \overload
\fn int QStringRef::compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
\since 4.5
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index f4d6fc24a5..d5101b7ff3 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -110,6 +110,15 @@ public:
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QLatin1Char front() const { return at(0); }
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QLatin1Char back() const { return at(size() - 1); }
+ Q_REQUIRED_RESULT int compare(QStringView other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return QtPrivate::compareStrings(*this, other, cs); }
+ Q_REQUIRED_RESULT int compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return QtPrivate::compareStrings(*this, other, cs); }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR int compare(QChar c) const noexcept
+ { return isEmpty() || front() == c ? size() - 1 : uchar(m_data[0]) - c.unicode() ; }
+ Q_REQUIRED_RESULT int compare(QChar c, Qt::CaseSensitivity cs) const noexcept
+ { return QtPrivate::compareStrings(*this, QStringView(&c, 1), cs); }
+
Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::startsWith(*this, s, cs); }
Q_REQUIRED_RESULT bool startsWith(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
@@ -232,6 +241,8 @@ Q_DECL_CONSTEXPR bool QtPrivate::isLatin1(QLatin1String) noexcept
//
// QStringView members that require QLatin1String:
//
+int QStringView::compare(QLatin1String s, Qt::CaseSensitivity cs) const noexcept
+{ return QtPrivate::compareStrings(*this, s, cs); }
bool QStringView::startsWith(QLatin1String s, Qt::CaseSensitivity cs) const noexcept
{ return QtPrivate::startsWith(*this, s, cs); }
bool QStringView::endsWith(QLatin1String s, Qt::CaseSensitivity cs) const noexcept
@@ -729,6 +740,8 @@ public:
#endif
int compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
inline int compare(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
+ int compare(QChar ch, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return compare(QStringView{&ch, 1}, cs); }
static inline int compare(const QString &s1, const QString &s2,
Qt::CaseSensitivity cs = Qt::CaseSensitive) noexcept
@@ -1615,6 +1628,8 @@ public:
int compare(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
int compare(const QStringRef &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
+ int compare(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
+ { return QtPrivate::compareStrings(*this, QStringView(&c, 1), cs); }
int compare(QLatin1String s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII)
int compare(const QByteArray &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
diff --git a/src/corelib/text/qstringview.cpp b/src/corelib/text/qstringview.cpp
index 08dade7e68..9df656dc59 100644
--- a/src/corelib/text/qstringview.cpp
+++ b/src/corelib/text/qstringview.cpp
@@ -692,15 +692,29 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \fn int QStringView::compare(QStringView other, Qt::CaseSensitivity cs) const
+ \fn int QStringView::compare(QStringView str, Qt::CaseSensitivity cs) const
\since 5.12
- Compares this string-view with the \a other string-view and returns an
- integer less than, equal to, or greater than zero if this string-view
- is less than, equal to, or greater than the other string-view.
+ Returns an integer that compares to zero as this string-view compares to the
+ string-view \a str.
- If \a cs is Qt::CaseSensitive, the comparison is case sensitive;
- otherwise the comparison is case insensitive.
+ If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive;
+ otherwise the comparison is case-insensitive.
+
+ \sa operator==(), operator<(), operator>()
+*/
+
+/*!
+ \fn int QStringView::compare(QLatin1String l1, Qt::CaseSensitivity cs) const
+ \fn int QStringView::compare(QChar ch) const
+ \fn int QStringView::compare(QChar ch, Qt::CaseSensitivity cs) const
+ \since 5.14
+
+ Returns an integer that compares to zero as this string-view compares to the
+ Latin-1 string \a l1, or character \a ch, respectively.
+
+ If \a cs is Qt::CaseSensitive (the default), the comparison is case sensitive;
+ otherwise the comparison is case-insensitive.
\sa operator==(), operator<(), operator>()
*/
diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h
index 06391ffef4..83418970a5 100644
--- a/src/corelib/text/qstringview.h
+++ b/src/corelib/text/qstringview.h
@@ -257,6 +257,11 @@ public:
Q_REQUIRED_RESULT int compare(QStringView other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::compareStrings(*this, other, cs); }
+ Q_REQUIRED_RESULT inline int compare(QLatin1String other, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept;
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR int compare(QChar c) const noexcept
+ { return empty() || front() == c ? size() - 1 : *utf16() - c.unicode() ; }
+ Q_REQUIRED_RESULT int compare(QChar c, Qt::CaseSensitivity cs) const noexcept
+ { return QtPrivate::compareStrings(*this, QStringView(&c, 1), cs); }
Q_REQUIRED_RESULT bool startsWith(QStringView s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const noexcept
{ return QtPrivate::startsWith(*this, s, cs); }
diff --git a/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp b/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp
index 3870237ac3..9043ee6361 100644
--- a/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp
+++ b/src/gui/doc/snippets/code/src_gui_image_qpixmapcache.cpp
@@ -49,9 +49,8 @@
****************************************************************************/
//! [0]
-QPixmap* pp;
QPixmap p;
-if ((pp=QPixmapCache::find("my_big_image", pm))) {
+if (QPixmap *pp = QPixmapCache::find("my_big_image"))) {
p = *pp;
} else {
p.load("bigimage.png");
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index ce0c6170c1..189f12fd5c 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -68,6 +68,11 @@
#include <private/qimage_p.h>
#include <private/qfont_p.h>
+#if QT_CONFIG(thread)
+#include "qsemaphore.h"
+#include "qthreadpool.h"
+#endif
+
QT_BEGIN_NAMESPACE
static inline bool isLocked(QImageData *data)
@@ -4861,18 +4866,43 @@ void QImage::applyColorTransform(const QColorTransform &transform)
Q_UNREACHABLE();
}
+ std::function<void(int,int)> transformSegment;
+
if (depth() > 32) {
- for (int i = 0; i < height(); ++i) {
- QRgba64 *scanline = reinterpret_cast<QRgba64 *>(scanLine(i));
- transform.d->apply(scanline, scanline, width(), flags);
- }
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ QRgba64 *scanline = reinterpret_cast<QRgba64 *>(scanLine(y));
+ transform.d->apply(scanline, scanline, width(), flags);
+ }
+ };
} else {
- for (int i = 0; i < height(); ++i) {
- QRgb *scanline = reinterpret_cast<QRgb *>(scanLine(i));
- transform.d->apply(scanline, scanline, width(), flags);
- }
+ transformSegment = [&](int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ QRgb *scanline = reinterpret_cast<QRgb *>(scanLine(y));
+ transform.d->apply(scanline, scanline, width(), flags);
+ }
+ };
}
+#if QT_CONFIG(thread)
+ int segments = sizeInBytes() / (1<<16);
+ segments = std::min(segments, height());
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (height() - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ transformSegment(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ } else
+#endif
+ transformSegment(0, height());
+
if (oldFormat != format())
*this = std::move(*this).convertToFormat(oldFormat);
}
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 27088698ec..4f570d8684 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -43,7 +43,12 @@
#include <private/qendian_p.h>
#include <private/qsimd_p.h>
#include <private/qimage_p.h>
+
#include <qendian.h>
+#if QT_CONFIG(thread)
+#include <qsemaphore.h>
+#include <qthreadpool.h>
+#endif
QT_BEGIN_NAMESPACE
@@ -159,12 +164,8 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
// Cannot be used with indexed formats.
Q_ASSERT(dest->format > QImage::Format_Indexed8);
Q_ASSERT(src->format > QImage::Format_Indexed8);
- uint buf[BufferSize];
- uint *buffer = buf;
const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
- const uchar *srcData = src->data;
- uchar *destData = dest->data;
FetchAndConvertPixelsFunc fetch = srcLayout->fetchToARGB32PM;
ConvertAndStorePixelsFunc store = destLayout->storeFromARGB32PM;
@@ -197,59 +198,110 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
else
store = destLayout->storeFromRGB32;
}
- QDitherInfo dither;
- QDitherInfo *ditherPtr = nullptr;
- if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
- ditherPtr = &dither;
-
- for (int y = 0; y < src->height; ++y) {
- dither.y = y;
- int x = 0;
- while (x < src->width) {
- dither.x = x;
- int l = src->width - x;
- if (destLayout->bpp == QPixelLayout::BPP32)
- buffer = reinterpret_cast<uint *>(destData) + x;
- else
- l = qMin(l, BufferSize);
- const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
- store(destData, ptr, x, l, nullptr, ditherPtr);
- x += l;
+
+ auto convertSegment = [=](int yStart, int yEnd) {
+ uint buf[BufferSize];
+ uint *buffer = buf;
+ const uchar *srcData = src->data + src->bytes_per_line * yStart;
+ uchar *destData = dest->data + dest->bytes_per_line * yStart;
+ QDitherInfo dither;
+ QDitherInfo *ditherPtr = nullptr;
+ if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
+ ditherPtr = &dither;
+ for (int y = yStart; y < yEnd; ++y) {
+ dither.y = y;
+ int x = 0;
+ while (x < src->width) {
+ dither.x = x;
+ int l = src->width - x;
+ if (destLayout->bpp == QPixelLayout::BPP32)
+ buffer = reinterpret_cast<uint *>(destData) + x;
+ else
+ l = qMin(l, BufferSize);
+ const uint *ptr = fetch(buffer, srcData, x, l, 0, ditherPtr);
+ store(destData, ptr, x, l, 0, ditherPtr);
+ x += l;
+ }
+ srcData += src->bytes_per_line;
+ destData += dest->bytes_per_line;
}
- srcData += src->bytes_per_line;
- destData += dest->bytes_per_line;
- }
+ };
+
+#if QT_CONFIG(thread)
+ int segments = src->nbytes / (1<<16);
+ segments = std::min(segments, src->height);
+
+ if (segments <= 1)
+ return convertSegment(0, src->height);
+
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (src->height - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ convertSegment(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+#else
+ convertSegment(0, src->height);
+#endif
}
void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
Q_ASSERT(dest->format > QImage::Format_Indexed8);
Q_ASSERT(src->format > QImage::Format_Indexed8);
- QRgba64 buf[BufferSize];
- QRgba64 *buffer = buf;
const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
- const uchar *srcData = src->data;
- uchar *destData = dest->data;
const FetchAndConvertPixelsFunc64 fetch = srcLayout->fetchToRGBA64PM;
const ConvertAndStorePixelsFunc64 store = qStoreFromRGBA64PM[dest->format];
- for (int y = 0; y < src->height; ++y) {
- int x = 0;
- while (x < src->width) {
- int l = src->width - x;
- if (destLayout->bpp == QPixelLayout::BPP64)
- buffer = reinterpret_cast<QRgba64 *>(destData) + x;
- else
- l = qMin(l, BufferSize);
- const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
- store(destData, ptr, x, l, nullptr, nullptr);
- x += l;
+ auto convertSegment = [=](int yStart, int yEnd) {
+ QRgba64 buf[BufferSize];
+ QRgba64 *buffer = buf;
+ const uchar *srcData = src->data + yStart * src->bytes_per_line;
+ uchar *destData = dest->data + yStart * dest->bytes_per_line;
+ for (int y = yStart; y < yEnd; ++y) {
+ int x = 0;
+ while (x < src->width) {
+ int l = src->width - x;
+ if (destLayout->bpp == QPixelLayout::BPP64)
+ buffer = reinterpret_cast<QRgba64 *>(destData) + x;
+ else
+ l = qMin(l, BufferSize);
+ const QRgba64 *ptr = fetch(buffer, srcData, x, l, nullptr, nullptr);
+ store(destData, ptr, x, l, nullptr, nullptr);
+ x += l;
+ }
+ srcData += src->bytes_per_line;
+ destData += dest->bytes_per_line;
}
- srcData += src->bytes_per_line;
- destData += dest->bytes_per_line;
- }
+ };
+#if QT_CONFIG(thread)
+ int segments = src->nbytes / (1<<16);
+ segments = std::min(segments, src->height);
+
+ if (segments <= 1)
+ return convertSegment(0, src->height);
+
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (src->height - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ convertSegment(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+#else
+ convertSegment(0, src->height);
+#endif
}
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags flags)
@@ -270,11 +322,6 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
&& qt_highColorPrecision(dst_format, !srcLayout->hasAlphaChannel))
return false;
- uint buf[BufferSize];
- uint *buffer = buf;
- uchar *srcData = data->data;
- uchar *destData = data->data;
-
QImageData::ImageSizeParameters params = { data->bytes_per_line, data->nbytes };
if (data->depth != destDepth) {
params = QImageData::calculateImageParameters(data->width, data->height, destDepth);
@@ -313,28 +360,52 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
else
store = destLayout->storeFromRGB32;
}
- QDitherInfo dither;
- QDitherInfo *ditherPtr = nullptr;
- if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
- ditherPtr = &dither;
-
- for (int y = 0; y < data->height; ++y) {
- dither.y = y;
- int x = 0;
- while (x < data->width) {
- dither.x = x;
- int l = data->width - x;
- if (srcLayout->bpp == QPixelLayout::BPP32)
- buffer = reinterpret_cast<uint *>(srcData) + x;
- else
- l = qMin(l, BufferSize);
- const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
- store(destData, ptr, x, l, nullptr, ditherPtr);
- x += l;
+
+ auto convertSegment = [=](int yStart, int yEnd) {
+ uint buf[BufferSize];
+ uint *buffer = buf;
+ uchar *srcData = data->data + data->bytes_per_line * yStart;
+ uchar *destData = srcData;
+ QDitherInfo dither;
+ QDitherInfo *ditherPtr = nullptr;
+ if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
+ ditherPtr = &dither;
+ for (int y = yStart; y < yEnd; ++y) {
+ dither.y = y;
+ int x = 0;
+ while (x < data->width) {
+ dither.x = x;
+ int l = data->width - x;
+ if (srcLayout->bpp == QPixelLayout::BPP32)
+ buffer = reinterpret_cast<uint *>(srcData) + x;
+ else
+ l = qMin(l, BufferSize);
+ const uint *ptr = fetch(buffer, srcData, x, l, nullptr, ditherPtr);
+ store(destData, ptr, x, l, nullptr, ditherPtr);
+ x += l;
+ }
+ srcData += data->bytes_per_line;
+ destData += params.bytesPerLine;
}
- srcData += data->bytes_per_line;
- destData += params.bytesPerLine;
- }
+ };
+#if QT_CONFIG(thread)
+ int segments = data->nbytes / (1<<16);
+ segments = std::min(segments, data->height);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (data->height - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ convertSegment(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ } else
+#endif
+ convertSegment(0, data->height);
if (params.totalSize != data->nbytes) {
Q_ASSERT(params.totalSize < data->nbytes);
void *newData = realloc(data->data, params.totalSize);
diff --git a/src/gui/painting/qimagescale.cpp b/src/gui/painting/qimagescale.cpp
index 2e2f65b483..ecb0230e71 100644
--- a/src/gui/painting/qimagescale.cpp
+++ b/src/gui/painting/qimagescale.cpp
@@ -43,6 +43,11 @@
#include "qcolor.h"
#include "qrgba64_p.h"
+#if QT_CONFIG(thread)
+#include "qsemaphore.h"
+#include "qthreadpool.h"
+#endif
+
QT_BEGIN_NAMESPACE
/*
@@ -239,6 +244,8 @@ static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img,
isi = new QImageScaleInfo;
if (!isi)
return nullptr;
+ isi->sh = sh;
+ isi->sw = sw;
isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1);
@@ -303,33 +310,54 @@ static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest,
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- /* calculate the source line we'll scan from */
- const unsigned int *sptr = ypoints[y];
- unsigned int *dptr = dest + (y * dow);
- const int yap = yapoints[y];
- if (yap > 0) {
- for (int x = 0; x < dw; x++) {
- const unsigned int *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap);
- else
- *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap);
- dptr++;
- }
- } else {
- for (int x = 0; x < dw; x++) {
- const unsigned int *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap);
- else
- *dptr = pix[0];
- dptr++;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ /* calculate the source line we'll scan from */
+ const unsigned int *sptr = ypoints[y];
+ unsigned int *dptr = dest + (y * dow);
+ const int yap = yapoints[y];
+ if (yap > 0) {
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap);
+ else
+ *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap);
+ dptr++;
+ }
+ } else {
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
+ dptr++;
+ }
}
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
/* scale by area sampling - with alpha */
@@ -411,33 +439,54 @@ static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b, a;
- qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a);
-
- int xap = xapoints[x];
- if (xap > 0) {
- int rr, gg, bb, aa;
- qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
-
- r = r * (256 - xap);
- g = g * (256 - xap);
- b = b * (256 - xap);
- a = a * (256 - xap);
- r = (r + (rr * xap)) >> 8;
- g = (g + (gg * xap)) >> 8;
- b = (b + (bb * xap)) >> 8;
- a = (a + (aa * xap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b, a;
+ qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ int rr, gg, bb, aa;
+ qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
+
+ r = r * (256 - xap);
+ g = g * (256 - xap);
+ b = b * (256 - xap);
+ a = a * (256 - xap);
+ r = (r + (rr * xap)) >> 8;
+ g = (g + (gg * xap)) >> 8;
+ b = (b + (bb * xap)) >> 8;
+ a = (a + (aa * xap)) >> 8;
+ }
+ *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
}
- *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
@@ -449,34 +498,55 @@ static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b, a;
- qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a);
-
- int yap = yapoints[y];
- if (yap > 0) {
- int rr, gg, bb, aa;
- qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
-
- r = r * (256 - yap);
- g = g * (256 - yap);
- b = b * (256 - yap);
- a = a * (256 - yap);
- r = (r + (rr * yap)) >> 8;
- g = (g + (gg * yap)) >> 8;
- b = (b + (bb * yap)) >> 8;
- a = (a + (aa * yap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b, a;
+ qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ int rr, gg, bb, aa;
+ qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
+
+ r = r * (256 - yap);
+ g = g * (256 - yap);
+ b = b * (256 - yap);
+ a = a * (256 - yap);
+ r = (r + (rr * yap)) >> 8;
+ g = (g + (gg * yap)) >> 8;
+ b = (b + (bb * yap)) >> 8;
+ a = (a + (aa * yap)) >> 8;
+ }
+ *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
+ dptr++;
}
- *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest,
@@ -487,45 +557,66 @@ static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *des
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = (yapoints[y]) >> 16;
- int yap = (yapoints[y]) & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int rx, gx, bx, ax;
- qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
- int r = ((rx>>4) * yap);
- int g = ((gx>>4) * yap);
- int b = ((bx>>4) * yap);
- int a = ((ax>>4) * yap);
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int rx, gx, bx, ax;
+ qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ int r = ((rx>>4) * yap);
+ int g = ((gx>>4) * yap);
+ int b = ((bx>>4) * yap);
+ int a = ((ax>>4) * yap);
+
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ r += ((rx>>4) * Cy);
+ g += ((gx>>4) * Cy);
+ b += ((bx>>4) * Cy);
+ a += ((ax>>4) * Cy);
+ }
sptr += sow;
qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += ((rx>>4) * Cy);
- g += ((gx>>4) * Cy);
- b += ((bx>>4) * Cy);
- a += ((ax>>4) * Cy);
- }
- sptr += sow;
- qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += ((rx>>4) * j);
- g += ((gx>>4) * j);
- b += ((bx>>4) * j);
- a += ((ax>>4) * j);
+ r += ((rx>>4) * j);
+ g += ((gx>>4) * j);
+ b += ((bx>>4) * j);
+ a += ((ax>>4) * j);
- *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24);
- dptr++;
+ *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24);
+ dptr++;
+ }
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
#if QT_CONFIG(raster_64bit)
@@ -546,32 +637,53 @@ static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- const QRgba64 *sptr = ypoints[y];
- QRgba64 *dptr = dest + (y * dow);
- const int yap = yapoints[y];
- if (yap > 0) {
- for (int x = 0; x < dw; x++) {
- const QRgba64 *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256);
- else
- *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap);
- dptr++;
- }
- } else {
- for (int x = 0; x < dw; x++) {
- const QRgba64 *pix = sptr + xpoints[x];
- const int xap = xapoints[x];
- if (xap > 0)
- *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap);
- else
- *dptr = pix[0];
- dptr++;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const QRgba64 *sptr = ypoints[y];
+ QRgba64 *dptr = dest + (y * dow);
+ const int yap = yapoints[y];
+ if (yap > 0) {
+ for (int x = 0; x < dw; x++) {
+ const QRgba64 *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256);
+ else
+ *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap);
+ dptr++;
+ }
+ } else {
+ for (int x = 0; x < dw; x++) {
+ const QRgba64 *pix = sptr + xpoints[x];
+ const int xap = xapoints[x];
+ if (xap > 0)
+ *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap);
+ else
+ *dptr = pix[0];
+ dptr++;
+ }
}
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest,
@@ -616,33 +728,54 @@ static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = (yapoints[y]) >> 16;
- int yap = (yapoints[y]) & 0xffff;
-
- QRgba64 *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const QRgba64 *sptr = ypoints[y] + xpoints[x];
- qint64 r, g, b, a;
- qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a);
-
- int xap = xapoints[x];
- if (xap > 0) {
- qint64 rr, gg, bb, aa;
- qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
-
- r = r * (256 - xap);
- g = g * (256 - xap);
- b = b * (256 - xap);
- a = a * (256 - xap);
- r = (r + (rr * xap)) >> 8;
- g = (g + (gg * xap)) >> 8;
- b = (b + (bb * xap)) >> 8;
- a = (a + (aa * xap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgba64 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const QRgba64 *sptr = ypoints[y] + xpoints[x];
+ qint64 r, g, b, a;
+ qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ qint64 rr, gg, bb, aa;
+ qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
+
+ r = r * (256 - xap);
+ g = g * (256 - xap);
+ b = b * (256 - xap);
+ a = a * (256 - xap);
+ r = (r + (rr * xap)) >> 8;
+ g = (g + (gg * xap)) >> 8;
+ b = (b + (bb * xap)) >> 8;
+ a = (a + (aa * xap)) >> 8;
+ }
+ *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
}
- *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest,
@@ -653,34 +786,55 @@ static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- QRgba64 *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const QRgba64 *sptr = ypoints[y] + xpoints[x];
- qint64 r, g, b, a;
- qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a);
-
- int yap = yapoints[y];
- if (yap > 0) {
- qint64 rr, gg, bb, aa;
- qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
-
- r = r * (256 - yap);
- g = g * (256 - yap);
- b = b * (256 - yap);
- a = a * (256 - yap);
- r = (r + (rr * yap)) >> 8;
- g = (g + (gg * yap)) >> 8;
- b = (b + (bb * yap)) >> 8;
- a = (a + (aa * yap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ QRgba64 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgba64 *sptr = ypoints[y] + xpoints[x];
+ qint64 r, g, b, a;
+ qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ qint64 rr, gg, bb, aa;
+ qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
+
+ r = r * (256 - yap);
+ g = g * (256 - yap);
+ b = b * (256 - yap);
+ a = a * (256 - yap);
+ r = (r + (rr * yap)) >> 8;
+ g = (g + (gg * yap)) >> 8;
+ b = (b + (bb * yap)) >> 8;
+ a = (a + (aa * yap)) >> 8;
+ }
+ *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
+ dptr++;
}
- *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
@@ -691,43 +845,64 @@ static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = (yapoints[y]) >> 16;
- int yap = (yapoints[y]) & 0xffff;
-
- QRgba64 *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const QRgba64 *sptr = ypoints[y] + xpoints[x];
- qint64 rx, gx, bx, ax;
- qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
-
- qint64 r = rx * yap;
- qint64 g = gx * yap;
- qint64 b = bx * yap;
- qint64 a = ax * yap;
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = (yapoints[y]) >> 16;
+ int yap = (yapoints[y]) & 0xffff;
+
+ QRgba64 *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const QRgba64 *sptr = ypoints[y] + xpoints[x];
+ qint64 rx, gx, bx, ax;
+ qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+
+ qint64 r = rx * yap;
+ qint64 g = gx * yap;
+ qint64 b = bx * yap;
+ qint64 a = ax * yap;
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
+ r += rx * Cy;
+ g += gx * Cy;
+ b += bx * Cy;
+ a += ax * Cy;
+ }
sptr += sow;
qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += rx * Cy;
- g += gx * Cy;
- b += bx * Cy;
- a += ax * Cy;
+ r += rx * j;
+ g += gx * j;
+ b += bx * j;
+ a += ax * j;
+
+ *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28);
+ dptr++;
}
- sptr += sow;
- qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
- r += rx * j;
- g += gx * j;
- b += bx * j;
- a += ax * j;
-
- *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28);
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
#endif
@@ -817,31 +992,52 @@ static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b;
- qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b);
-
- int xap = xapoints[x];
- if (xap > 0) {
- int rr, bb, gg;
- qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb);
-
- r = r * (256 - xap);
- g = g * (256 - xap);
- b = b * (256 - xap);
- r = (r + (rr * xap)) >> 8;
- g = (g + (gg * xap)) >> 8;
- b = (b + (bb * xap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b;
+ qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ int rr, bb, gg;
+ qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb);
+
+ r = r * (256 - xap);
+ g = g * (256 - xap);
+ b = b * (256 - xap);
+ r = (r + (rr * xap)) >> 8;
+ g = (g + (gg * xap)) >> 8;
+ b = (b + (bb * xap)) >> 8;
+ }
+ *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
- *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
@@ -853,31 +1049,52 @@ static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int r, g, b;
- qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b);
-
- int yap = yapoints[y];
- if (yap > 0) {
- int rr, bb, gg;
- qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb);
-
- r = r * (256 - yap);
- g = g * (256 - yap);
- b = b * (256 - yap);
- r = (r + (rr * yap)) >> 8;
- g = (g + (gg * yap)) >> 8;
- b = (b + (bb * yap)) >> 8;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int r, g, b;
+ qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ int rr, bb, gg;
+ qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb);
+
+ r = r * (256 - yap);
+ g = g * (256 - yap);
+ b = b * (256 - yap);
+ r = (r + (rr * yap)) >> 8;
+ g = (g + (gg * yap)) >> 8;
+ b = (b + (bb * yap)) >> 8;
+ }
+ *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
- *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest,
@@ -888,43 +1105,64 @@ static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ int rx, gx, bx;
+ qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- int rx, gx, bx;
- qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
+ int r = (rx >> 4) * yap;
+ int g = (gx >> 4) * yap;
+ int b = (bx >> 4) * yap;
- int r = (rx >> 4) * yap;
- int g = (gx >> 4) * yap;
- int b = (bx >> 4) * yap;
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ r += (rx >> 4) * Cy;
+ g += (gx >> 4) * Cy;
+ b += (bx >> 4) * Cy;
+ }
sptr += sow;
qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
- r += (rx >> 4) * Cy;
- g += (gx >> 4) * Cy;
- b += (bx >> 4) * Cy;
- }
- sptr += sow;
- qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
-
- r += (rx >> 4) * j;
- g += (gx >> 4) * j;
- b += (bx >> 4) * j;
+ r += (rx >> 4) * j;
+ g += (gx >> 4) * j;
+ b += (bx >> 4) * j;
- *dptr = qRgb(r >> 24, g >> 24, b >> 24);
- dptr++;
+ *dptr = qRgb(r >> 24, g >> 24, b >> 24);
+ dptr++;
+ }
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
diff --git a/src/gui/painting/qimagescale_neon.cpp b/src/gui/painting/qimagescale_neon.cpp
index 4ae113b002..416155e139 100644
--- a/src/gui/painting/qimagescale_neon.cpp
+++ b/src/gui/painting/qimagescale_neon.cpp
@@ -41,6 +41,11 @@
#include "qimage.h"
#include <private/qsimd_p.h>
+#if QT_CONFIG(thread)
+#include "qsemaphore.h"
+#include "qthreadpool.h"
+#endif
+
#if defined(__ARM_NEON__)
QT_BEGIN_NAMESPACE
@@ -76,33 +81,54 @@ void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *d
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow);
-
- int xap = xapoints[x];
- if (xap > 0) {
- uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow);
-
- vx = vmulq_n_u32(vx, 256 - xap);
- vr = vmulq_n_u32(vr, xap);
- vx = vaddq_u32(vx, vr);
- vx = vshrq_n_u32(vx, 8);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow);
+
+ int xap = xapoints[x];
+ if (xap > 0) {
+ uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow);
+
+ vx = vmulq_n_u32(vx, 256 - xap);
+ vr = vmulq_n_u32(vr, xap);
+ vx = vaddq_u32(vx, vr);
+ vx = vshrq_n_u32(vx, 8);
+ }
+ vx = vshrq_n_u32(vx, 14);
+ const uint16x4_t vx16 = vmovn_u32(vx);
+ const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
+ *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = vshrq_n_u32(vx, 14);
- const uint16x4_t vx16 = vmovn_u32(vx);
- const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
- *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
template<bool RGB>
@@ -115,33 +141,54 @@ void qt_qimageScaleAARGBA_down_x_up_y_neon(QImageScaleInfo *isi, unsigned int *d
int *yapoints = isi->yapoints;
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
-
- int yap = yapoints[y];
- if (yap > 0) {
- uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1);
-
- vx = vmulq_n_u32(vx, 256 - yap);
- vr = vmulq_n_u32(vr, yap);
- vx = vaddq_u32(vx, vr);
- vx = vshrq_n_u32(vx, 8);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ uint32x4_t vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1);
+
+ vx = vmulq_n_u32(vx, 256 - yap);
+ vr = vmulq_n_u32(vr, yap);
+ vx = vaddq_u32(vx, vr);
+ vx = vshrq_n_u32(vx, 8);
+ }
+ vx = vshrq_n_u32(vx, 14);
+ const uint16x4_t vx16 = vmovn_u32(vx);
+ const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
+ *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = vshrq_n_u32(vx, 14);
- const uint16x4_t vx16 = vmovn_u32(vx);
- const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
- *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
template<bool RGB>
@@ -153,43 +200,64 @@ void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const int Cx = xapoints[x] >> 16;
- const int xap = xapoints[x] & 0xffff;
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const int Cx = xapoints[x] >> 16;
+ const int xap = xapoints[x] & 0xffff;
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
- vx = vshrq_n_u32(vx, 4);
- uint32x4_t vr = vmulq_n_u32(vx, yap);
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ uint32x4_t vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
+ vx = vshrq_n_u32(vx, 4);
+ uint32x4_t vr = vmulq_n_u32(vx, yap);
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
+ vx = vshrq_n_u32(vx, 4);
+ vx = vmulq_n_u32(vx, Cy);
+ vr = vaddq_u32(vr, vx);
+ }
sptr += sow;
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
vx = vshrq_n_u32(vx, 4);
- vx = vmulq_n_u32(vx, Cy);
+ vx = vmulq_n_u32(vx, j);
vr = vaddq_u32(vr, vx);
+
+ vx = vshrq_n_u32(vr, 24);
+ const uint16x4_t vx16 = vmovn_u32(vx);
+ const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
+ *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- sptr += sow;
- vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1);
- vx = vshrq_n_u32(vx, 4);
- vx = vmulq_n_u32(vx, j);
- vr = vaddq_u32(vr, vx);
-
- vx = vshrq_n_u32(vr, 24);
- const uint16x4_t vx16 = vmovn_u32(vx);
- const uint8x8_t vx8 = vmovn_u16(vcombine_u16(vx16, vx16));
- *dptr = vget_lane_u32(vreinterpret_u32_u8(vx8), 0);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
template void qt_qimageScaleAARGBA_up_x_down_y_neon<false>(QImageScaleInfo *isi, unsigned int *dest,
diff --git a/src/gui/painting/qimagescale_p.h b/src/gui/painting/qimagescale_p.h
index 244d681718..a9a4c0f858 100644
--- a/src/gui/painting/qimagescale_p.h
+++ b/src/gui/painting/qimagescale_p.h
@@ -66,6 +66,8 @@ namespace QImageScale {
int *xapoints{nullptr};
int *yapoints{nullptr};
int xup_yup{0};
+ int sh = 0;
+ int sw = 0;
};
}
diff --git a/src/gui/painting/qimagescale_sse4.cpp b/src/gui/painting/qimagescale_sse4.cpp
index 5861a2e2ff..902ae61ed2 100644
--- a/src/gui/painting/qimagescale_sse4.cpp
+++ b/src/gui/painting/qimagescale_sse4.cpp
@@ -42,6 +42,11 @@
#include <private/qdrawhelper_x86_p.h>
#include <private/qsimd_p.h>
+#if QT_CONFIG(thread)
+#include "qsemaphore.h"
+#include "qthreadpool.h"
+#endif
+
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
QT_BEGIN_NAMESPACE
@@ -70,44 +75,65 @@ void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *d
int dw, int dh, int dow, int sow)
{
const unsigned int **ypoints = isi->ypoints;
- int *xpoints = isi->xpoints;
- int *xapoints = isi->xapoints;
- int *yapoints = isi->yapoints;
+ const int *xpoints = isi->xpoints;
+ const int *xapoints = isi->xapoints;
+ const int *yapoints = isi->yapoints;
const __m128i v256 = _mm_set1_epi32(256);
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
- const __m128i vCy = _mm_set1_epi32(Cy);
- const __m128i vyap = _mm_set1_epi32(yap);
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- __m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy);
-
- int xap = xapoints[x];
- if (xap > 0) {
- const __m128i vxap = _mm_set1_epi32(xap);
- const __m128i vinvxap = _mm_sub_epi32(v256, vxap);
- __m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ const int Cy = yapoints[y] >> 16;
+ const int yap = yapoints[y] & 0xffff;
+ const __m128i vCy = _mm_set1_epi32(Cy);
+ const __m128i vyap = _mm_set1_epi32(yap);
- vx = _mm_mullo_epi32(vx, vinvxap);
- vr = _mm_mullo_epi32(vr, vxap);
- vx = _mm_add_epi32(vx, vr);
- vx = _mm_srli_epi32(vx, 8);
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ __m128i vx = qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, vyap, vCy);
+
+ const int xap = xapoints[x];
+ if (xap > 0) {
+ const __m128i vxap = _mm_set1_epi32(xap);
+ const __m128i vinvxap = _mm_sub_epi32(v256, vxap);
+ __m128i vr = qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, vyap, vCy);
+
+ vx = _mm_mullo_epi32(vx, vinvxap);
+ vr = _mm_mullo_epi32(vr, vxap);
+ vx = _mm_add_epi32(vx, vr);
+ vx = _mm_srli_epi32(vx, 8);
+ }
+ vx = _mm_srli_epi32(vx, 14);
+ vx = _mm_packus_epi32(vx, vx);
+ vx = _mm_packus_epi16(vx, vx);
+ *dptr = _mm_cvtsi128_si32(vx);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = _mm_srli_epi32(vx, 14);
- vx = _mm_packus_epi32(vx, _mm_setzero_si128());
- vx = _mm_packus_epi16(vx, _mm_setzero_si128());
- *dptr = _mm_cvtsi128_si32(vx);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
template<bool RGB>
@@ -122,37 +148,58 @@ void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *d
const __m128i v256 = _mm_set1_epi32(256);
/* go through every scanline in the output buffer */
- for (int y = 0; y < dh; y++) {
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- int Cx = xapoints[x] >> 16;
- int xap = xapoints[x] & 0xffff;
- const __m128i vCx = _mm_set1_epi32(Cx);
- const __m128i vxap = _mm_set1_epi32(xap);
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
-
- int yap = yapoints[y];
- if (yap > 0) {
- const __m128i vyap = _mm_set1_epi32(yap);
- const __m128i vinvyap = _mm_sub_epi32(v256, vyap);
- __m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx);
-
- vx = _mm_mullo_epi32(vx, vinvyap);
- vr = _mm_mullo_epi32(vr, vyap);
- vx = _mm_add_epi32(vx, vr);
- vx = _mm_srli_epi32(vx, 8);
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ int Cx = xapoints[x] >> 16;
+ int xap = xapoints[x] & 0xffff;
+ const __m128i vCx = _mm_set1_epi32(Cx);
+ const __m128i vxap = _mm_set1_epi32(xap);
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
+
+ int yap = yapoints[y];
+ if (yap > 0) {
+ const __m128i vyap = _mm_set1_epi32(yap);
+ const __m128i vinvyap = _mm_sub_epi32(v256, vyap);
+ __m128i vr = qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, vxap, vCx);
+
+ vx = _mm_mullo_epi32(vx, vinvyap);
+ vr = _mm_mullo_epi32(vr, vyap);
+ vx = _mm_add_epi32(vx, vr);
+ vx = _mm_srli_epi32(vx, 8);
+ }
+ vx = _mm_srli_epi32(vx, 14);
+ vx = _mm_packus_epi32(vx, vx);
+ vx = _mm_packus_epi16(vx, vx);
+ *dptr = _mm_cvtsi128_si32(vx);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- vx = _mm_srli_epi32(vx, 14);
- vx = _mm_packus_epi32(vx, _mm_setzero_si128());
- vx = _mm_packus_epi16(vx, _mm_setzero_si128());
- *dptr = _mm_cvtsi128_si32(vx);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
template<bool RGB>
@@ -164,42 +211,63 @@ void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest,
int *xapoints = isi->xapoints;
int *yapoints = isi->yapoints;
- for (int y = 0; y < dh; y++) {
- int Cy = yapoints[y] >> 16;
- int yap = yapoints[y] & 0xffff;
- const __m128i vCy = _mm_set1_epi32(Cy);
- const __m128i vyap = _mm_set1_epi32(yap);
-
- unsigned int *dptr = dest + (y * dow);
- for (int x = 0; x < dw; x++) {
- const int Cx = xapoints[x] >> 16;
- const int xap = xapoints[x] & 0xffff;
- const __m128i vCx = _mm_set1_epi32(Cx);
- const __m128i vxap = _mm_set1_epi32(xap);
-
- const unsigned int *sptr = ypoints[y] + xpoints[x];
- __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
- __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap);
-
- int j;
- for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ auto scaleSection = [&] (int yStart, int yEnd) {
+ for (int y = yStart; y < yEnd; ++y) {
+ int Cy = yapoints[y] >> 16;
+ int yap = yapoints[y] & 0xffff;
+ const __m128i vCy = _mm_set1_epi32(Cy);
+ const __m128i vyap = _mm_set1_epi32(yap);
+
+ unsigned int *dptr = dest + (y * dow);
+ for (int x = 0; x < dw; x++) {
+ const int Cx = xapoints[x] >> 16;
+ const int xap = xapoints[x] & 0xffff;
+ const __m128i vCx = _mm_set1_epi32(Cx);
+ const __m128i vxap = _mm_set1_epi32(xap);
+
+ const unsigned int *sptr = ypoints[y] + xpoints[x];
+ __m128i vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
+ __m128i vr = _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vyap);
+
+ int j;
+ for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
+ sptr += sow;
+ vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
+ vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy));
+ }
sptr += sow;
vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
- vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), vCy));
+ vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j)));
+
+ vr = _mm_srli_epi32(vr, 24);
+ vr = _mm_packus_epi32(vr, _mm_setzero_si128());
+ vr = _mm_packus_epi16(vr, _mm_setzero_si128());
+ *dptr = _mm_cvtsi128_si32(vr);
+ if (RGB)
+ *dptr |= 0xff000000;
+ dptr++;
}
- sptr += sow;
- vx = qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, vxap, vCx);
- vr = _mm_add_epi32(vr, _mm_mullo_epi32(_mm_srli_epi32(vx, 4), _mm_set1_epi32(j)));
-
- vr = _mm_srli_epi32(vr, 24);
- vr = _mm_packus_epi32(vr, _mm_setzero_si128());
- vr = _mm_packus_epi16(vr, _mm_setzero_si128());
- *dptr = _mm_cvtsi128_si32(vr);
- if (RGB)
- *dptr |= 0xff000000;
- dptr++;
}
+ };
+#if QT_CONFIG(thread)
+ int segments = (qsizetype(isi->sh) * isi->sw) / (1<<16);
+ segments = std::min(segments, dh);
+ if (segments > 1) {
+ QSemaphore semaphore;
+ int y = 0;
+ for (int i = 0; i < segments; ++i) {
+ int yn = (dh - y) / (segments - i);
+ QThreadPool::globalInstance()->start([&, y, yn]() {
+ scaleSection(y, y + yn);
+ semaphore.release(1);
+ });
+ y += yn;
+ }
+ semaphore.acquire(segments);
+ return;
}
+#endif
+ scaleSection(0, dh);
}
template void qt_qimageScaleAARGBA_up_x_down_y_sse4<false>(QImageScaleInfo *isi, unsigned int *dest,
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index 11623c78f0..e3cdc218b2 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1603,25 +1603,6 @@ QPainterPath QPainterPath::toReversed() const
}
/*!
- \overload
-
- Converts the path into a list of polygons without any transformation,
- and returns the list.
-
- This function creates one polygon for each subpath regardless of
- intersecting subpaths (i.e. overlapping bounding rectangles). To
- make sure that such overlapping subpaths are filled correctly, use
- the toFillPolygons() function instead.
-
- \sa toFillPolygons(), toFillPolygon(), {QPainterPath#QPainterPath
- Conversion}{QPainterPath Conversion}
-*/
-QList<QPolygonF> QPainterPath::toSubpathPolygons() const
-{
- return toSubpathPolygons(QTransform());
-}
-
-/*!
Converts the path into a list of polygons using the QTransform
\a matrix, and returns the list.
@@ -1679,35 +1660,6 @@ QList<QPolygonF> QPainterPath::toSubpathPolygons(const QTransform &matrix) const
}
/*!
- \overload
-
- Converts the path into a list of polygons without any transformation,
- and returns the list.
-
- The function differs from the toFillPolygon() function in that it
- creates several polygons. It is provided because it is usually
- faster to draw several small polygons than to draw one large
- polygon, even though the total number of points drawn is the same.
-
- The toFillPolygons() function differs from the toSubpathPolygons()
- function in that it create only polygon for subpaths that have
- overlapping bounding rectangles.
-
- Like the toFillPolygon() function, this function uses a rewinding
- technique to make sure that overlapping subpaths can be filled
- using the correct fill rule. Note that rewinding inserts addition
- lines in the polygons so the outline of the fill polygon does not
- match the outline of the path.
-
- \sa toSubpathPolygons(), toFillPolygon(),
- {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
-*/
-QList<QPolygonF> QPainterPath::toFillPolygons() const
-{
- return toFillPolygons(QTransform());
-}
-
-/*!
Converts the path into a list of polygons using the
QTransform \a matrix, and returns the list.
@@ -2903,28 +2855,6 @@ void QPainterPathStroker::setDashOffset(qreal offset)
}
/*!
- \overload
-
- Converts the path into a polygon without any transformation,
- and returns the polygon.
-
- The polygon is created by first converting all subpaths to
- polygons, then using a rewinding technique to make sure that
- overlapping subpaths can be filled using the correct fill rule.
-
- Note that rewinding inserts addition lines in the polygon so
- the outline of the fill polygon does not match the outline of
- the path.
-
- \sa toSubpathPolygons(), toFillPolygons(),
- {QPainterPath#QPainterPath Conversion}{QPainterPath Conversion}
-*/
-QPolygonF QPainterPath::toFillPolygon() const
-{
- return toFillPolygon(QTransform());
-}
-
-/*!
Converts the path into a polygon using the QTransform
\a matrix, and returns the polygon.
diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h
index 078b665222..aa43c74bee 100644
--- a/src/gui/painting/qpainterpath.h
+++ b/src/gui/painting/qpainterpath.h
@@ -41,6 +41,7 @@
#define QPAINTERPATH_H
#include <QtGui/qtguiglobal.h>
+#include <QtGui/qtransform.h>
#include <QtCore/qglobal.h>
#include <QtCore/qrect.h>
#include <QtCore/qline.h>
@@ -176,12 +177,9 @@ public:
Q_REQUIRED_RESULT QPainterPath toReversed() const;
- QList<QPolygonF> toSubpathPolygons() const;
- QList<QPolygonF> toSubpathPolygons(const QTransform &matrix) const;
- QList<QPolygonF> toFillPolygons() const;
- QList<QPolygonF> toFillPolygons(const QTransform &matrix) const;
- QPolygonF toFillPolygon() const;
- QPolygonF toFillPolygon(const QTransform &matrix) const;
+ QList<QPolygonF> toSubpathPolygons(const QTransform &matrix = QTransform()) const;
+ QList<QPolygonF> toFillPolygons(const QTransform &matrix = QTransform()) const;
+ QPolygonF toFillPolygon(const QTransform &matrix = QTransform()) const;
int elementCount() const;
QPainterPath::Element elementAt(int i) const;
@@ -356,6 +354,8 @@ inline void QPainterPath::translate(const QPointF &offset)
inline QPainterPath QPainterPath::translated(const QPointF &offset) const
{ return translated(offset.x(), offset.y()); }
+inline QPainterPath operator *(const QPainterPath &p, const QTransform &m)
+{ return m.map(p); }
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QPainterPath &);
diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp
index cd31d75f83..f3c193d799 100644
--- a/src/gui/painting/qrasterizer.cpp
+++ b/src/gui/painting/qrasterizer.cpp
@@ -46,6 +46,8 @@
#include <private/qdatabuffer_p.h>
#include <private/qdrawhelper_p.h>
+#include <QtGui/qpainterpath.h>
+
#include <algorithm>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index e906397520..3728060caf 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -43,6 +43,8 @@
#include "private/qfontengine_p.h"
#include "private/qnumeric_p.h"
+#include <QtGui/qpainterpath.h>
+
QT_BEGIN_NAMESPACE
// #define CACHE_DEBUG
diff --git a/src/gui/painting/qtransform.h b/src/gui/painting/qtransform.h
index 351f2b2e4e..d235f15029 100644
--- a/src/gui/painting/qtransform.h
+++ b/src/gui/painting/qtransform.h
@@ -40,7 +40,6 @@
#define QTRANSFORM_H
#include <QtGui/qtguiglobal.h>
-#include <QtGui/qpainterpath.h>
#include <QtGui/qpolygon.h>
#include <QtGui/qregion.h>
#include <QtGui/qwindowdefs.h>
@@ -50,8 +49,8 @@
QT_BEGIN_NAMESPACE
-
class QVariant;
+class QPainterPath;
class Q_GUI_EXPORT QTransform
{
@@ -406,8 +405,6 @@ inline QPolygonF operator *(const QPolygonF &a, const QTransform &m)
{ return m.map(a); }
inline QRegion operator *(const QRegion &r, const QTransform &m)
{ return m.map(r); }
-inline QPainterPath operator *(const QPainterPath &p, const QTransform &m)
-{ return m.map(p); }
inline QTransform operator *(const QTransform &a, qreal n)
{ QTransform t(a); t *= n; return t; }
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index c805e23ad0..83c1e8eaa2 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -2885,16 +2885,57 @@ QRhiShaderResourceBinding QRhiShaderResourceBinding::uniformBufferWithDynamicOff
\return a shader resource binding for the given binding number, pipeline
stages, texture, and sampler specified by \a binding, \a stage, \a tex,
\a sampler.
+
+ \note This function is equivalent to calling sampledTextures() with a
+ \c count of 1.
+
+ \sa sampledTextures()
*/
QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTexture(
int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
{
+ const TextureAndSampler texSampler = { tex, sampler };
+ return sampledTextures(binding, stage, 1, &texSampler);
+}
+
+/*!
+ \return a shader resource binding for the given binding number, pipeline
+ stages, and the array of texture-sampler pairs specified by \a binding, \a
+ stage, \a count, and \a texSamplers.
+
+ \note \a count must be at least 1, and not larger than 16.
+
+ \note When \a count is 1, this function is equivalent to sampledTexture().
+
+ This function is relevant when arrays of combined image samplers are
+ involved. For example, in GLSL \c{layout(binding = 5) uniform sampler2D
+ shadowMaps[8];} declares an array of combined image samplers. The
+ application is then expected provide a QRhiShaderResourceBinding for
+ binding point 5, set up by calling this function with \a count set to 8 and
+ a valid texture and sampler for each element of the array.
+
+ \warning All elements of the array must be specified. With the above
+ example, the only valid, portable approach is calling this function with a
+ \a count of 8. Additionally, all QRhiTexture and QRhiSampler instances must
+ be valid, meaning nullptr is not an accepted value. This is due to some of
+ the underlying APIs, such as, Vulkan, that require a valid image and
+ sampler object for each element in descriptor arrays. Applications are
+ advised to provide "dummy" samplers and textures if some array elements are
+ not relevant (due to not being accessed in the shader).
+
+ \sa sampledTexture()
+ */
+QRhiShaderResourceBinding QRhiShaderResourceBinding::sampledTextures(
+ int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers)
+{
+ Q_ASSERT(count >= 1 && count <= Data::MAX_TEX_SAMPLER_ARRAY_SIZE);
QRhiShaderResourceBinding b;
b.d.binding = binding;
b.d.stage = stage;
b.d.type = SampledTexture;
- b.d.u.stex.tex = tex;
- b.d.u.stex.sampler = sampler;
+ b.d.u.stex.count = count;
+ for (int i = 0; i < count; ++i)
+ b.d.u.stex.texSamplers[i] = texSamplers[i];
return b;
}
@@ -3084,10 +3125,14 @@ bool operator==(const QRhiShaderResourceBinding &a, const QRhiShaderResourceBind
}
break;
case QRhiShaderResourceBinding::SampledTexture:
- if (da->u.stex.tex != db->u.stex.tex
- || da->u.stex.sampler != db->u.stex.sampler)
- {
+ if (da->u.stex.count != db->u.stex.count)
return false;
+ for (int i = 0; i < da->u.stex.count; ++i) {
+ if (da->u.stex.texSamplers[i].tex != db->u.stex.texSamplers[i].tex
+ || da->u.stex.texSamplers[i].sampler != db->u.stex.texSamplers[i].sampler)
+ {
+ return false;
+ }
}
break;
case QRhiShaderResourceBinding::ImageLoad:
@@ -3162,10 +3207,13 @@ QDebug operator<<(QDebug dbg, const QRhiShaderResourceBinding &b)
<< ')';
break;
case QRhiShaderResourceBinding::SampledTexture:
- dbg.nospace() << " SampledTexture("
- << "texture=" << d->u.stex.tex
- << " sampler=" << d->u.stex.sampler
- << ')';
+ dbg.nospace() << " SampledTextures("
+ << "count=" << d->u.stex.count;
+ for (int i = 0; i < d->u.stex.count; ++i) {
+ dbg.nospace() << " texture=" << d->u.stex.texSamplers[i].tex
+ << " sampler=" << d->u.stex.texSamplers[i].sampler;
+ }
+ dbg.nospace() << ')';
break;
case QRhiShaderResourceBinding::ImageLoad:
dbg.nospace() << " ImageLoad("
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h
index 17c911a5ff..9d906d7bbd 100644
--- a/src/gui/rhi/qrhi_p.h
+++ b/src/gui/rhi/qrhi_p.h
@@ -348,6 +348,12 @@ public:
static QRhiShaderResourceBinding sampledTexture(int binding, StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler);
+ struct TextureAndSampler {
+ QRhiTexture *tex;
+ QRhiSampler *sampler;
+ };
+ static QRhiShaderResourceBinding sampledTextures(int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers);
+
static QRhiShaderResourceBinding imageLoad(int binding, StageFlags stage, QRhiTexture *tex, int level);
static QRhiShaderResourceBinding imageStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
static QRhiShaderResourceBinding imageLoadStore(int binding, StageFlags stage, QRhiTexture *tex, int level);
@@ -370,9 +376,10 @@ public:
int maybeSize;
bool hasDynamicOffset;
};
+ static const int MAX_TEX_SAMPLER_ARRAY_SIZE = 16;
struct SampledTextureData {
- QRhiTexture *tex;
- QRhiSampler *sampler;
+ int count;
+ TextureAndSampler texSamplers[MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct StorageImageData {
QRhiTexture *tex;
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 7b583e6fd2..ed202958f3 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -113,6 +113,10 @@ QT_BEGIN_NAMESPACE
#define DXGI_ADAPTER_FLAG_SOFTWARE 2
#endif
+#ifndef D3D11_1_UAV_SLOT_COUNT
+#define D3D11_1_UAV_SLOT_COUNT 64
+#endif
+
QRhiD3D11::QRhiD3D11(QRhiD3D11InitParams *params, QRhiD3D11NativeHandles *importDevice)
: ofr(this),
deviceCurse(this)
@@ -627,18 +631,25 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex);
- QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler);
- if (texD->generation != bd.stex.texGeneration
- || texD->m_id != bd.stex.texId
- || samplerD->generation != bd.stex.samplerGeneration
- || samplerD->m_id != bd.stex.samplerId)
- {
+ const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ if (bd.stex.count != data->count) {
+ bd.stex.count = data->count;
srbUpdate = true;
- bd.stex.texId = texD->m_id;
- bd.stex.texGeneration = texD->generation;
- bd.stex.samplerId = samplerD->m_id;
- bd.stex.samplerGeneration = samplerD->generation;
+ }
+ for (int elem = 0; elem < data->count; ++elem) {
+ QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
+ QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
+ if (texD->generation != bd.stex.d[elem].texGeneration
+ || texD->m_id != bd.stex.d[elem].texId
+ || samplerD->generation != bd.stex.d[elem].samplerGeneration
+ || samplerD->m_id != bd.stex.d[elem].samplerId)
+ {
+ srbUpdate = true;
+ bd.stex.d[elem].texId = texD->m_id;
+ bd.stex.d[elem].texGeneration = texD->generation;
+ bd.stex.d[elem].samplerId = samplerD->m_id;
+ bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ }
}
}
break;
@@ -1894,31 +1905,38 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex);
- QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler);
- bd.stex.texId = texD->m_id;
- bd.stex.texGeneration = texD->generation;
- bd.stex.samplerId = samplerD->m_id;
- bd.stex.samplerGeneration = samplerD->generation;
- if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
- if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
- res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv });
- res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState });
+ const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ bd.stex.count = data->count;
+ const QPair<int, int> nativeBindingVert = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
+ const QPair<int, int> nativeBindingFrag = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
+ const QPair<int, int> nativeBindingComp = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
+ // if SPIR-V binding b is mapped to tN and sN in HLSL, and it
+ // is an array, then it will use tN, tN+1, tN+2, ..., and sN,
+ // sN+1, sN+2, ...
+ for (int elem = 0; elem < data->count; ++elem) {
+ QD3D11Texture *texD = QRHI_RES(QD3D11Texture, data->texSamplers[elem].tex);
+ QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, data->texSamplers[elem].sampler);
+ bd.stex.d[elem].texId = texD->m_id;
+ bd.stex.d[elem].texGeneration = texD->generation;
+ bd.stex.d[elem].samplerId = samplerD->m_id;
+ bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
+ if (nativeBindingVert.first >= 0 && nativeBindingVert.second >= 0) {
+ res[RBM_VERTEX].textures.append({ nativeBindingVert.first + elem, texD->srv });
+ res[RBM_VERTEX].samplers.append({ nativeBindingVert.second + elem, samplerD->samplerState });
+ }
}
- }
- if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
- if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
- res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv });
- res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState });
+ if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
+ if (nativeBindingFrag.first >= 0 && nativeBindingFrag.second >= 0) {
+ res[RBM_FRAGMENT].textures.append({ nativeBindingFrag.first + elem, texD->srv });
+ res[RBM_FRAGMENT].samplers.append({ nativeBindingFrag.second + elem, samplerD->samplerState });
+ }
}
- }
- if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
- if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
- res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv });
- res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState });
+ if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
+ if (nativeBindingComp.first >= 0 && nativeBindingComp.second >= 0) {
+ res[RBM_COMPUTE].textures.append({ nativeBindingComp.first + elem, texD->srv });
+ res[RBM_COMPUTE].samplers.append({ nativeBindingComp.second + elem, samplerD->samplerState });
+ }
}
}
}
@@ -2077,102 +2095,156 @@ static void applyDynamicOffsets(QVarLengthArray<UINT, 4> *offsets,
}
}
+static inline uint clampedResourceCount(uint startSlot, int countSlots, uint maxSlots, const char *resType)
+{
+ if (startSlot + countSlots > maxSlots) {
+ qWarning("Not enough D3D11 %s slots to bind %d resources starting at slot %d, max slots is %d",
+ resType, countSlots, startSlot, maxSlots);
+ countSlots = maxSlots > startSlot ? maxSlots - startSlot : 0;
+ }
+ return countSlots;
+}
+
void QRhiD3D11::bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange)
{
if (!offsetOnlyChange) {
- for (const auto &batch : srbD->vssamplers.batches)
- context->VSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
+ for (const auto &batch : srbD->vssamplers.batches) {
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
+ D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "VS sampler");
+ if (count)
+ context->VSSetSamplers(batch.startBinding, count, batch.resources.constData());
+ }
for (const auto &batch : srbD->vsshaderresources.batches) {
- context->VSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
- contextState.vsHighestActiveSrvBinding = qMax<int>(contextState.vsHighestActiveSrvBinding,
- int(batch.startBinding) + batch.resources.count() - 1);
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
+ D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "VS SRV");
+ if (count) {
+ context->VSSetShaderResources(batch.startBinding, count, batch.resources.constData());
+ contextState.vsHighestActiveSrvBinding = qMax(contextState.vsHighestActiveSrvBinding,
+ int(batch.startBinding + count) - 1);
+ }
}
- for (const auto &batch : srbD->fssamplers.batches)
- context->PSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
+ for (const auto &batch : srbD->fssamplers.batches) {
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
+ D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "PS sampler");
+ if (count)
+ context->PSSetSamplers(batch.startBinding, count, batch.resources.constData());
+ }
for (const auto &batch : srbD->fsshaderresources.batches) {
- context->PSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
- contextState.fsHighestActiveSrvBinding = qMax<int>(contextState.fsHighestActiveSrvBinding,
- int(batch.startBinding) + batch.resources.count() - 1);
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
+ D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "PS SRV");
+ if (count) {
+ context->PSSetShaderResources(batch.startBinding, count, batch.resources.constData());
+ contextState.fsHighestActiveSrvBinding = qMax(contextState.fsHighestActiveSrvBinding,
+ int(batch.startBinding + count) - 1);
+ }
}
- for (const auto &batch : srbD->cssamplers.batches)
- context->CSSetSamplers(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
+ for (const auto &batch : srbD->cssamplers.batches) {
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
+ D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT, "CS sampler");
+ if (count)
+ context->CSSetSamplers(batch.startBinding, count, batch.resources.constData());
+ }
for (const auto &batch : srbD->csshaderresources.batches) {
- context->CSSetShaderResources(batch.startBinding, UINT(batch.resources.count()), batch.resources.constData());
- contextState.csHighestActiveSrvBinding = qMax<int>(contextState.csHighestActiveSrvBinding,
- int(batch.startBinding) + batch.resources.count() - 1);
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
+ D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT, "CS SRV");
+ if (count) {
+ context->CSSetShaderResources(batch.startBinding, count, batch.resources.constData());
+ contextState.csHighestActiveSrvBinding = qMax(contextState.csHighestActiveSrvBinding,
+ int(batch.startBinding + count) - 1);
+ }
}
}
for (int i = 0, ie = srbD->vsubufs.batches.count(); i != ie; ++i) {
- if (!dynOfsPairCount) {
- context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
- UINT(srbD->vsubufs.batches[i].resources.count()),
- srbD->vsubufs.batches[i].resources.constData(),
- srbD->vsubufoffsets.batches[i].resources.constData(),
- srbD->vsubufsizes.batches[i].resources.constData());
- } else {
- QVarLengthArray<UINT, 4> offsets;
- applyDynamicOffsets(&offsets, i, &srbD->vsubufs, &srbD->vsubufoffsets, dynOfsPairs, dynOfsPairCount);
- context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
- UINT(srbD->vsubufs.batches[i].resources.count()),
- srbD->vsubufs.batches[i].resources.constData(),
- offsets.constData(),
- srbD->vsubufsizes.batches[i].resources.constData());
+ const uint count = clampedResourceCount(srbD->vsubufs.batches[i].startBinding,
+ srbD->vsubufs.batches[i].resources.count(),
+ D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT,
+ "VS cbuf");
+ if (count) {
+ if (!dynOfsPairCount) {
+ context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
+ count,
+ srbD->vsubufs.batches[i].resources.constData(),
+ srbD->vsubufoffsets.batches[i].resources.constData(),
+ srbD->vsubufsizes.batches[i].resources.constData());
+ } else {
+ QVarLengthArray<UINT, 4> offsets;
+ applyDynamicOffsets(&offsets, i, &srbD->vsubufs, &srbD->vsubufoffsets, dynOfsPairs, dynOfsPairCount);
+ context->VSSetConstantBuffers1(srbD->vsubufs.batches[i].startBinding,
+ count,
+ srbD->vsubufs.batches[i].resources.constData(),
+ offsets.constData(),
+ srbD->vsubufsizes.batches[i].resources.constData());
+ }
}
}
for (int i = 0, ie = srbD->fsubufs.batches.count(); i != ie; ++i) {
- if (!dynOfsPairCount) {
- context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
- UINT(srbD->fsubufs.batches[i].resources.count()),
- srbD->fsubufs.batches[i].resources.constData(),
- srbD->fsubufoffsets.batches[i].resources.constData(),
- srbD->fsubufsizes.batches[i].resources.constData());
- } else {
- QVarLengthArray<UINT, 4> offsets;
- applyDynamicOffsets(&offsets, i, &srbD->fsubufs, &srbD->fsubufoffsets, dynOfsPairs, dynOfsPairCount);
- context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
- UINT(srbD->fsubufs.batches[i].resources.count()),
- srbD->fsubufs.batches[i].resources.constData(),
- offsets.constData(),
- srbD->fsubufsizes.batches[i].resources.constData());
+ const uint count = clampedResourceCount(srbD->fsubufs.batches[i].startBinding,
+ srbD->fsubufs.batches[i].resources.count(),
+ D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT,
+ "PS cbuf");
+ if (count) {
+ if (!dynOfsPairCount) {
+ context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
+ count,
+ srbD->fsubufs.batches[i].resources.constData(),
+ srbD->fsubufoffsets.batches[i].resources.constData(),
+ srbD->fsubufsizes.batches[i].resources.constData());
+ } else {
+ QVarLengthArray<UINT, 4> offsets;
+ applyDynamicOffsets(&offsets, i, &srbD->fsubufs, &srbD->fsubufoffsets, dynOfsPairs, dynOfsPairCount);
+ context->PSSetConstantBuffers1(srbD->fsubufs.batches[i].startBinding,
+ count,
+ srbD->fsubufs.batches[i].resources.constData(),
+ offsets.constData(),
+ srbD->fsubufsizes.batches[i].resources.constData());
+ }
}
}
for (int i = 0, ie = srbD->csubufs.batches.count(); i != ie; ++i) {
- if (!dynOfsPairCount) {
- context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
- UINT(srbD->csubufs.batches[i].resources.count()),
- srbD->csubufs.batches[i].resources.constData(),
- srbD->csubufoffsets.batches[i].resources.constData(),
- srbD->csubufsizes.batches[i].resources.constData());
- } else {
- QVarLengthArray<UINT, 4> offsets;
- applyDynamicOffsets(&offsets, i, &srbD->csubufs, &srbD->csubufoffsets, dynOfsPairs, dynOfsPairCount);
- context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
- UINT(srbD->csubufs.batches[i].resources.count()),
- srbD->csubufs.batches[i].resources.constData(),
- offsets.constData(),
- srbD->csubufsizes.batches[i].resources.constData());
+ const uint count = clampedResourceCount(srbD->csubufs.batches[i].startBinding,
+ srbD->csubufs.batches[i].resources.count(),
+ D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT,
+ "CS cbuf");
+ if (count) {
+ if (!dynOfsPairCount) {
+ context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
+ count,
+ srbD->csubufs.batches[i].resources.constData(),
+ srbD->csubufoffsets.batches[i].resources.constData(),
+ srbD->csubufsizes.batches[i].resources.constData());
+ } else {
+ QVarLengthArray<UINT, 4> offsets;
+ applyDynamicOffsets(&offsets, i, &srbD->csubufs, &srbD->csubufoffsets, dynOfsPairs, dynOfsPairCount);
+ context->CSSetConstantBuffers1(srbD->csubufs.batches[i].startBinding,
+ count,
+ srbD->csubufs.batches[i].resources.constData(),
+ offsets.constData(),
+ srbD->csubufsizes.batches[i].resources.constData());
+ }
}
}
- for (int i = 0, ie = srbD->csUAVs.batches.count(); i != ie; ++i) {
- const uint startBinding = srbD->csUAVs.batches[i].startBinding;
- const uint count = uint(srbD->csUAVs.batches[i].resources.count());
- context->CSSetUnorderedAccessViews(startBinding,
- count,
- srbD->csUAVs.batches[i].resources.constData(),
- nullptr);
- contextState.csHighestActiveUavBinding = qMax<int>(contextState.csHighestActiveUavBinding,
- int(startBinding + count - 1));
+ for (const auto &batch : srbD->csUAVs.batches) {
+ const uint count = clampedResourceCount(batch.startBinding, batch.resources.count(),
+ D3D11_1_UAV_SLOT_COUNT, "CS UAV");
+ if (count) {
+ context->CSSetUnorderedAccessViews(batch.startBinding,
+ count,
+ batch.resources.constData(),
+ nullptr);
+ contextState.csHighestActiveUavBinding = qMax(contextState.csHighestActiveUavBinding,
+ int(batch.startBinding + count) - 1);
+ }
}
}
@@ -3529,11 +3601,15 @@ static pD3DCompile resolveD3DCompile()
static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error, QShaderKey *usedShaderKey)
{
- QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant });
- if (!dxbc.shader().isEmpty())
+ QShaderKey key = { QShader::DxbcShader, 50, shaderVariant };
+ QShaderCode dxbc = shader.shader(key);
+ if (!dxbc.shader().isEmpty()) {
+ if (usedShaderKey)
+ *usedShaderKey = key;
return dxbc.shader();
+ }
- const QShaderKey key = { QShader::HlslShader, 50, shaderVariant };
+ key = { QShader::HlslShader, 50, shaderVariant };
QShaderCode hlslSource = shader.shader(key);
if (hlslSource.shader().isEmpty()) {
qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader;
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
index f749b612b5..33412b8011 100644
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ b/src/gui/rhi/qrhid3d11_p_p.h
@@ -210,10 +210,13 @@ struct QD3D11ShaderResourceBindings : public QRhiShaderResourceBindings
uint generation;
};
struct BoundSampledTextureData {
- quint64 texId;
- uint texGeneration;
- quint64 samplerId;
- uint samplerGeneration;
+ int count;
+ struct {
+ quint64 texId;
+ uint texGeneration;
+ quint64 samplerId;
+ uint samplerGeneration;
+ } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct BoundStorageImageData {
quint64 id;
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index 4a442bc582..ea9bce08e4 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -917,10 +917,12 @@ void QRhiGles2::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
hasDynamicOffsetInSrb = true;
break;
case QRhiShaderResourceBinding::SampledTexture:
- trackedRegisterTexture(&passResTracker,
- QRHI_RES(QGles2Texture, b->u.stex.tex),
- QRhiPassResourceTracker::TexSample,
- QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
+ for (int elem = 0; elem < b->u.stex.count; ++elem) {
+ trackedRegisterTexture(&passResTracker,
+ QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex),
+ QRhiPassResourceTracker::TexSample,
+ QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
+ }
break;
case QRhiShaderResourceBinding::ImageLoad:
case QRhiShaderResourceBinding::ImageStore:
@@ -2572,36 +2574,37 @@ void QRhiGles2::bindShaderResources(QRhiGraphicsPipeline *maybeGraphicsPs, QRhiC
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.tex);
- QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b->u.stex.sampler);
QVector<QGles2SamplerDescription> &samplers(maybeGraphicsPs ? QRHI_RES(QGles2GraphicsPipeline, maybeGraphicsPs)->samplers
: QRHI_RES(QGles2ComputePipeline, maybeComputePs)->samplers);
-
- for (QGles2SamplerDescription &sampler : samplers) {
- if (sampler.binding == b->binding) {
- f->glActiveTexture(GL_TEXTURE0 + uint(texUnit));
- f->glBindTexture(texD->target, texD->texture);
-
- if (texD->samplerState != samplerD->d) {
- f->glTexParameteri(texD->target, GL_TEXTURE_MIN_FILTER, GLint(samplerD->d.glminfilter));
- f->glTexParameteri(texD->target, GL_TEXTURE_MAG_FILTER, GLint(samplerD->d.glmagfilter));
- f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_S, GLint(samplerD->d.glwraps));
- f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_T, GLint(samplerD->d.glwrapt));
- // 3D textures not supported by GLES 2.0 or by us atm...
- //f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_R, samplerD->d.glwrapr);
- if (caps.textureCompareMode) {
- if (samplerD->d.gltexcomparefunc != GL_NEVER) {
- f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
- f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_FUNC, GLint(samplerD->d.gltexcomparefunc));
- } else {
- f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ for (int elem = 0; elem < b->u.stex.count; ++elem) {
+ QGles2Texture *texD = QRHI_RES(QGles2Texture, b->u.stex.texSamplers[elem].tex);
+ QGles2Sampler *samplerD = QRHI_RES(QGles2Sampler, b->u.stex.texSamplers[elem].sampler);
+ for (QGles2SamplerDescription &sampler : samplers) {
+ if (sampler.binding == b->binding) {
+ f->glActiveTexture(GL_TEXTURE0 + uint(texUnit));
+ f->glBindTexture(texD->target, texD->texture);
+
+ if (texD->samplerState != samplerD->d) {
+ f->glTexParameteri(texD->target, GL_TEXTURE_MIN_FILTER, GLint(samplerD->d.glminfilter));
+ f->glTexParameteri(texD->target, GL_TEXTURE_MAG_FILTER, GLint(samplerD->d.glmagfilter));
+ f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_S, GLint(samplerD->d.glwraps));
+ f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_T, GLint(samplerD->d.glwrapt));
+ // 3D textures not supported by GLES 2.0 or by us atm...
+ //f->glTexParameteri(texD->target, GL_TEXTURE_WRAP_R, samplerD->d.glwrapr);
+ if (caps.textureCompareMode) {
+ if (samplerD->d.gltexcomparefunc != GL_NEVER) {
+ f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
+ f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_FUNC, GLint(samplerD->d.gltexcomparefunc));
+ } else {
+ f->glTexParameteri(texD->target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+ }
}
+ texD->samplerState = samplerD->d;
}
- texD->samplerState = samplerD->d;
- }
- f->glUniform1i(sampler.glslLocation, texUnit);
- ++texUnit;
+ f->glUniform1i(sampler.glslLocation + elem, texUnit);
+ ++texUnit;
+ }
}
}
}
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 314c58b0b7..0806c8a052 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -748,30 +748,33 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
- QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
- if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- const int nativeBindingTexture = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture);
- const int nativeBindingSampler = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler);
- if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
- res[VERTEX].textures.append({ nativeBindingTexture, texD->d->tex });
- res[VERTEX].samplers.append({ nativeBindingSampler, samplerD->d->samplerState });
+ const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ for (int elem = 0; elem < data->count; ++elem) {
+ QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.texSamplers[elem].tex);
+ QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.texSamplers[elem].sampler);
+ if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
+ const int nativeBindingTexture = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture);
+ const int nativeBindingSampler = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler);
+ if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
+ res[VERTEX].textures.append({ nativeBindingTexture + elem, texD->d->tex });
+ res[VERTEX].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState });
+ }
}
- }
- if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- const int nativeBindingTexture = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
- const int nativeBindingSampler = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler);
- if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
- res[FRAGMENT].textures.append({ nativeBindingTexture, texD->d->tex });
- res[FRAGMENT].samplers.append({ nativeBindingSampler, samplerD->d->samplerState });
+ if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
+ const int nativeBindingTexture = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
+ const int nativeBindingSampler = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler);
+ if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
+ res[FRAGMENT].textures.append({ nativeBindingTexture + elem, texD->d->tex });
+ res[FRAGMENT].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState });
+ }
}
- }
- if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- const int nativeBindingTexture = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
- const int nativeBindingSampler = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler);
- if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
- res[COMPUTE].textures.append({ nativeBindingTexture, texD->d->tex });
- res[COMPUTE].samplers.append({ nativeBindingSampler, samplerD->d->samplerState });
+ if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
+ const int nativeBindingTexture = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
+ const int nativeBindingSampler = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler);
+ if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) {
+ res[COMPUTE].textures.append({ nativeBindingTexture + elem, texD->d->tex });
+ res[COMPUTE].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState });
+ }
}
}
}
@@ -1020,21 +1023,28 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
- QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
- if (texD->generation != bd.stex.texGeneration
- || texD->m_id != bd.stex.texId
- || samplerD->generation != bd.stex.samplerGeneration
- || samplerD->m_id != bd.stex.samplerId)
- {
+ const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ if (bd.stex.count != data->count) {
+ bd.stex.count = data->count;
resNeedsRebind = true;
- bd.stex.texId = texD->m_id;
- bd.stex.texGeneration = texD->generation;
- bd.stex.samplerId = samplerD->m_id;
- bd.stex.samplerGeneration = samplerD->generation;
}
- texD->lastActiveFrameSlot = currentFrameSlot;
- samplerD->lastActiveFrameSlot = currentFrameSlot;
+ for (int elem = 0; elem < data->count; ++elem) {
+ QMetalTexture *texD = QRHI_RES(QMetalTexture, data->texSamplers[elem].tex);
+ QMetalSampler *samplerD = QRHI_RES(QMetalSampler, data->texSamplers[elem].sampler);
+ if (texD->generation != bd.stex.d[elem].texGeneration
+ || texD->m_id != bd.stex.d[elem].texId
+ || samplerD->generation != bd.stex.d[elem].samplerGeneration
+ || samplerD->m_id != bd.stex.d[elem].samplerId)
+ {
+ resNeedsRebind = true;
+ bd.stex.d[elem].texId = texD->m_id;
+ bd.stex.d[elem].texGeneration = texD->generation;
+ bd.stex.d[elem].samplerId = samplerD->m_id;
+ bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ }
+ texD->lastActiveFrameSlot = currentFrameSlot;
+ samplerD->lastActiveFrameSlot = currentFrameSlot;
+ }
}
break;
case QRhiShaderResourceBinding::ImageLoad:
@@ -2981,12 +2991,16 @@ bool QMetalShaderResourceBindings::build()
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
- QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
- bd.stex.texId = texD->m_id;
- bd.stex.texGeneration = texD->generation;
- bd.stex.samplerId = samplerD->m_id;
- bd.stex.samplerGeneration = samplerD->generation;
+ const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ bd.stex.count = data->count;
+ for (int elem = 0; elem < data->count; ++elem) {
+ QMetalTexture *texD = QRHI_RES(QMetalTexture, data->texSamplers[elem].tex);
+ QMetalSampler *samplerD = QRHI_RES(QMetalSampler, data->texSamplers[elem].sampler);
+ bd.stex.d[elem].texId = texD->m_id;
+ bd.stex.d[elem].texGeneration = texD->generation;
+ bd.stex.d[elem].samplerId = samplerD->m_id;
+ bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ }
}
break;
case QRhiShaderResourceBinding::ImageLoad:
@@ -3241,8 +3255,12 @@ static inline MTLCullMode toMetalCullMode(QRhiGraphicsPipeline::CullMode c)
id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Variant shaderVariant,
QString *error, QByteArray *entryPoint, QShaderKey *activeKey)
{
- QShaderKey key = { QShader::MetalLibShader, 12, shaderVariant };
+ QShaderKey key = { QShader::MetalLibShader, 20, shaderVariant };
QShaderCode mtllib = shader.shader(key);
+ if (mtllib.shader().isEmpty()) {
+ key.setSourceVersion(12);
+ mtllib = shader.shader(key);
+ }
if (!mtllib.shader().isEmpty()) {
dispatch_data_t data = dispatch_data_create(mtllib.shader().constData(),
size_t(mtllib.shader().size()),
@@ -3261,16 +3279,20 @@ id<MTLLibrary> QRhiMetalData::createMetalLib(const QShader &shader, QShader::Var
}
}
- key = { QShader::MslShader, 12, shaderVariant };
+ key = { QShader::MslShader, 20, shaderVariant };
QShaderCode mslSource = shader.shader(key);
if (mslSource.shader().isEmpty()) {
- qWarning() << "No MSL 1.2 code found in baked shader" << shader;
+ key.setSourceVersion(12);
+ mslSource = shader.shader(key);
+ }
+ if (mslSource.shader().isEmpty()) {
+ qWarning() << "No MSL 2.0 or 1.2 code found in baked shader" << shader;
return nil;
}
NSString *src = [NSString stringWithUTF8String: mslSource.shader().constData()];
MTLCompileOptions *opts = [[MTLCompileOptions alloc] init];
- opts.languageVersion = MTLLanguageVersion1_2;
+ opts.languageVersion = key.sourceVersion() == 20 ? MTLLanguageVersion2_0 : MTLLanguageVersion1_2;
NSError *err = nil;
id<MTLLibrary> lib = [dev newLibraryWithSource: src options: opts error: &err];
[opts release];
diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h
index a5af5611a6..cb4b777d88 100644
--- a/src/gui/rhi/qrhimetal_p_p.h
+++ b/src/gui/rhi/qrhimetal_p_p.h
@@ -197,10 +197,13 @@ struct QMetalShaderResourceBindings : public QRhiShaderResourceBindings
uint generation;
};
struct BoundSampledTextureData {
- quint64 texId;
- uint texGeneration;
- quint64 samplerId;
- uint samplerGeneration;
+ int count;
+ struct {
+ quint64 texId;
+ uint texGeneration;
+ quint64 samplerId;
+ uint samplerGeneration;
+ } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct BoundStorageImageData {
quint64 id;
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index a92c3e14e9..26c153afff 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -345,6 +345,15 @@ static bool qvk_debug_filter(VkDebugReportFlagsEXT flags, VkDebugReportObjectTyp
return true;
}
+ // In certain cases allocateDescriptorSet() will attempt to allocate from a
+ // pool that does not have enough descriptors of a certain type. This makes
+ // the validation layer shout. However, this is not an error since we will
+ // then move on to another pool. If there is a real error, a qWarning
+ // message is shown by allocateDescriptorSet(), so the validation warning
+ // does not have any value and is just noise.
+ if (strstr(pMessage, "VUID-VkDescriptorSetAllocateInfo-descriptorPool-00307"))
+ return true;
+
return false;
}
@@ -2487,7 +2496,8 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
QVkShaderResourceBindings *srbD = QRHI_RES(QVkShaderResourceBindings, srb);
QVarLengthArray<VkDescriptorBufferInfo, 8> bufferInfos;
- QVarLengthArray<VkDescriptorImageInfo, 8> imageInfos;
+ using ArrayOfImageDesc = QVarLengthArray<VkDescriptorImageInfo, 8>;
+ QVarLengthArray<ArrayOfImageDesc, 8> imageInfos;
QVarLengthArray<VkWriteDescriptorSet, 12> writeInfos;
QVarLengthArray<QPair<int, int>, 12> infoIndices;
@@ -2530,17 +2540,22 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QVkTexture *texD = QRHI_RES(QVkTexture, b->u.stex.tex);
- QVkSampler *samplerD = QRHI_RES(QVkSampler, b->u.stex.sampler);
+ const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ writeInfo.descriptorCount = data->count; // arrays of combined image samplers are supported
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- bd.stex.texId = texD->m_id;
- bd.stex.texGeneration = texD->generation;
- bd.stex.samplerId = samplerD->m_id;
- bd.stex.samplerGeneration = samplerD->generation;
- VkDescriptorImageInfo imageInfo;
- imageInfo.sampler = samplerD->sampler;
- imageInfo.imageView = texD->imageView;
- imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ ArrayOfImageDesc imageInfo(data->count);
+ for (int elem = 0; elem < data->count; ++elem) {
+ QVkTexture *texD = QRHI_RES(QVkTexture, data->texSamplers[elem].tex);
+ QVkSampler *samplerD = QRHI_RES(QVkSampler, data->texSamplers[elem].sampler);
+ bd.stex.d[elem].texId = texD->m_id;
+ bd.stex.d[elem].texGeneration = texD->generation;
+ bd.stex.d[elem].samplerId = samplerD->m_id;
+ bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ imageInfo[elem].sampler = samplerD->sampler;
+ imageInfo[elem].imageView = texD->imageView;
+ imageInfo[elem].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ }
+ bd.stex.count = data->count;
imageInfoIndex = imageInfos.count();
imageInfos.append(imageInfo);
}
@@ -2555,10 +2570,10 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
bd.simage.id = texD->m_id;
bd.simage.generation = texD->generation;
- VkDescriptorImageInfo imageInfo;
- imageInfo.sampler = VK_NULL_HANDLE;
- imageInfo.imageView = view;
- imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
+ ArrayOfImageDesc imageInfo(1);
+ imageInfo[0].sampler = VK_NULL_HANDLE;
+ imageInfo[0].imageView = view;
+ imageInfo[0].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
imageInfoIndex = imageInfos.count();
imageInfos.append(imageInfo);
}
@@ -2596,7 +2611,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
if (bufferInfoIndex >= 0)
writeInfos[i].pBufferInfo = &bufferInfos[bufferInfoIndex];
else if (imageInfoIndex >= 0)
- writeInfos[i].pImageInfo = &imageInfos[imageInfoIndex];
+ writeInfos[i].pImageInfo = imageInfos[imageInfoIndex].constData();
}
df->vkUpdateDescriptorSets(dev, uint32_t(writeInfos.count()), writeInfos.constData(), 0, nullptr);
@@ -4210,24 +4225,30 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- QVkTexture *texD = QRHI_RES(QVkTexture, b->u.stex.tex);
- QVkSampler *samplerD = QRHI_RES(QVkSampler, b->u.stex.sampler);
- texD->lastActiveFrameSlot = currentFrameSlot;
- samplerD->lastActiveFrameSlot = currentFrameSlot;
- trackedRegisterTexture(&passResTracker, texD,
- QRhiPassResourceTracker::TexSample,
- QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
-
- if (texD->generation != bd.stex.texGeneration
- || texD->m_id != bd.stex.texId
- || samplerD->generation != bd.stex.samplerGeneration
- || samplerD->m_id != bd.stex.samplerId)
- {
+ const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex;
+ if (bd.stex.count != data->count) {
+ bd.stex.count = data->count;
rewriteDescSet = true;
- bd.stex.texId = texD->m_id;
- bd.stex.texGeneration = texD->generation;
- bd.stex.samplerId = samplerD->m_id;
- bd.stex.samplerGeneration = samplerD->generation;
+ }
+ for (int elem = 0; elem < data->count; ++elem) {
+ QVkTexture *texD = QRHI_RES(QVkTexture, data->texSamplers[elem].tex);
+ QVkSampler *samplerD = QRHI_RES(QVkSampler, data->texSamplers[elem].sampler);
+ texD->lastActiveFrameSlot = currentFrameSlot;
+ samplerD->lastActiveFrameSlot = currentFrameSlot;
+ trackedRegisterTexture(&passResTracker, texD,
+ QRhiPassResourceTracker::TexSample,
+ QRhiPassResourceTracker::toPassTrackerTextureStage(b->stage));
+ if (texD->generation != bd.stex.d[elem].texGeneration
+ || texD->m_id != bd.stex.d[elem].texId
+ || samplerD->generation != bd.stex.d[elem].samplerGeneration
+ || samplerD->m_id != bd.stex.d[elem].samplerId)
+ {
+ rewriteDescSet = true;
+ bd.stex.d[elem].texId = texD->m_id;
+ bd.stex.d[elem].texGeneration = texD->generation;
+ bd.stex.d[elem].samplerId = samplerD->m_id;
+ bd.stex.d[elem].samplerGeneration = samplerD->generation;
+ }
}
}
break;
@@ -6065,7 +6086,10 @@ bool QVkShaderResourceBindings::build()
memset(&vkbinding, 0, sizeof(vkbinding));
vkbinding.binding = uint32_t(b->binding);
vkbinding.descriptorType = toVkDescriptorType(b);
- vkbinding.descriptorCount = 1; // no array support yet
+ if (b->type == QRhiShaderResourceBinding::SampledTexture)
+ vkbinding.descriptorCount = b->u.stex.count;
+ else
+ vkbinding.descriptorCount = 1;
vkbinding.stageFlags = toVkShaderStageFlags(b->stage);
vkbindings.append(vkbinding);
}
diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h
index fd65417e75..62516e268d 100644
--- a/src/gui/rhi/qrhivulkan_p_p.h
+++ b/src/gui/rhi/qrhivulkan_p_p.h
@@ -254,10 +254,13 @@ struct QVkShaderResourceBindings : public QRhiShaderResourceBindings
uint generation;
};
struct BoundSampledTextureData {
- quint64 texId;
- uint texGeneration;
- quint64 samplerId;
- uint samplerGeneration;
+ int count;
+ struct {
+ quint64 texId;
+ uint texGeneration;
+ quint64 samplerId;
+ uint samplerGeneration;
+ } d[QRhiShaderResourceBinding::Data::MAX_TEX_SAMPLER_ARRAY_SIZE];
};
struct BoundStorageImageData {
quint64 id;
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index 884525bd76..b4b60cbaaf 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -51,6 +51,7 @@
#include <QtCore/qendian.h>
#include <QtCore/qfile.h>
+#include <QtGui/qpainterpath.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/vulkan/qvulkanwindow.cpp b/src/gui/vulkan/qvulkanwindow.cpp
index ee49cf0999..cb89b0b1e6 100644
--- a/src/gui/vulkan/qvulkanwindow.cpp
+++ b/src/gui/vulkan/qvulkanwindow.cpp
@@ -1602,7 +1602,7 @@ bool QVulkanWindow::event(QEvent *e)
\since 5.15
*/
-void QVulkanWindow::setQueueCreateInfoModifier(QueueCreateInfoModifier modifier)
+void QVulkanWindow::setQueueCreateInfoModifier(const QueueCreateInfoModifier &modifier)
{
Q_D(QVulkanWindow);
d->queueCreateInfoModifier = modifier;
diff --git a/src/gui/vulkan/qvulkanwindow.h b/src/gui/vulkan/qvulkanwindow.h
index 511b9501bd..a2d1c9995c 100644
--- a/src/gui/vulkan/qvulkanwindow.h
+++ b/src/gui/vulkan/qvulkanwindow.h
@@ -106,7 +106,7 @@ public:
typedef std::function<void(const VkQueueFamilyProperties *,
uint32_t,
QVector<VkDeviceQueueCreateInfo> &)> QueueCreateInfoModifier;
- void setQueueCreateInfoModifier(QueueCreateInfoModifier modifier);
+ void setQueueCreateInfoModifier(const QueueCreateInfoModifier &modifier);
bool isValid() const;
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 21d46011d7..d4df58e885 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -253,6 +253,7 @@ static void ensureInitialized()
/*!
\enum QNetworkAccessManager::NetworkAccessibility
+ \obsolete
Indicates whether the network is accessible via this network access manager.
@@ -268,6 +269,7 @@ static void ensureInitialized()
/*!
\property QNetworkAccessManager::networkAccessible
\brief whether the network is currently accessible via this network access manager.
+ \obsolete
\since 4.7
diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h
index 5194afb1be..f50dfbcca4 100644
--- a/src/network/access/qnetworkaccessmanager.h
+++ b/src/network/access/qnetworkaccessmanager.h
@@ -91,12 +91,15 @@ public:
};
#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
- enum NetworkAccessibility {
+ enum QT_DEPRECATED_VERSION_5_15 NetworkAccessibility {
UnknownAccessibility = -1,
NotAccessible = 0,
Accessible = 1
};
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
Q_ENUM(NetworkAccessibility)
+QT_WARNING_POP
#endif
explicit QNetworkAccessManager(QObject *parent = nullptr);
@@ -150,8 +153,11 @@ public:
QT_DEPRECATED_VERSION_5_15 QNetworkConfiguration configuration() const;
QT_DEPRECATED_VERSION_5_15 QNetworkConfiguration activeConfiguration() const;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QT_DEPRECATED_VERSION_5_15 void setNetworkAccessible(NetworkAccessibility accessible);
QT_DEPRECATED_VERSION_5_15 NetworkAccessibility networkAccessible() const;
+QT_WARNING_POP
#endif
#ifndef QT_NO_SSL
@@ -187,7 +193,14 @@ Q_SIGNALS:
#ifndef QT_NO_BEARERMANAGEMENT // ### Qt6: Remove section
QT_DEPRECATED_VERSION_5_15 void networkSessionConnected();
+#ifndef Q_MOC_RUN // moc has trouble with the expansion of these macros
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+#endif
QT_DEPRECATED_VERSION_5_15 void networkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
+#ifndef Q_MOC_RUN // moc has trouble with the expansion of these macros
+QT_WARNING_POP
+#endif
#endif
protected:
diff --git a/src/network/doc/qtnetwork.qdocconf b/src/network/doc/qtnetwork.qdocconf
index 5465b1c0af..8c7f3fc912 100644
--- a/src/network/doc/qtnetwork.qdocconf
+++ b/src/network/doc/qtnetwork.qdocconf
@@ -27,7 +27,7 @@ qhp.QtNetwork.subprojects.classes.sortPages = true
tagfile = ../../../doc/qtnetwork/qtnetwork.tags
-depends += qtcore qtgui qtdoc qmake
+depends += qtcore qtgui qtdoc qmake qtcmake
headerdirs += ..
diff --git a/src/network/doc/snippets/CMakeLists.txt b/src/network/doc/snippets/CMakeLists.txt
new file mode 100644
index 0000000000..a8030dd260
--- /dev/null
+++ b/src/network/doc/snippets/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.1.0)
+
+project(network_cppsnippets)
+
+add_executable(mytarget
+ network/tcpwait.cpp
+)
+
+# ![0]
+find_package(Qt5 COMPONENTS Network REQUIRED)
+target_link_libraries(mytarget Qt5::Network)
+# ![0]
diff --git a/src/network/doc/snippets/code/doc_src_qtnetwork.pro b/src/network/doc/snippets/code/doc_src_qtnetwork.pro
deleted file mode 100644
index a100943e58..0000000000
--- a/src/network/doc/snippets/code/doc_src_qtnetwork.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-#! [0]
-QT += network
-#! [0]
diff --git a/src/network/doc/snippets/network/tcpwait.cpp b/src/network/doc/snippets/network/tcpwait.cpp
index d57305930c..b81c5c1d53 100644
--- a/src/network/doc/snippets/network/tcpwait.cpp
+++ b/src/network/doc/snippets/network/tcpwait.cpp
@@ -48,7 +48,7 @@
**
****************************************************************************/
-#include <QtGui>
+#include <QCoreApplication>
#include <QTcpSocket>
int main(int argv, char **args)
diff --git a/src/network/doc/snippets/snippets.pro b/src/network/doc/snippets/snippets.pro
index 39153e0c8e..bdf854e454 100644
--- a/src/network/doc/snippets/snippets.pro
+++ b/src/network/doc/snippets/snippets.pro
@@ -2,6 +2,8 @@ TEMPLATE = app
TARGET = network_cppsnippets
+# ![0]
QT += network
+# ![0]
SOURCES += network/tcpwait.cpp
diff --git a/src/network/doc/src/bearermanagement.qdoc b/src/network/doc/src/bearermanagement.qdoc
index f8d6a807d2..8aec894269 100644
--- a/src/network/doc/src/bearermanagement.qdoc
+++ b/src/network/doc/src/bearermanagement.qdoc
@@ -31,6 +31,8 @@
\title Bearer Management
\brief An API to control the system's connectivity state.
+\warning Bearer management is deprecated and will be removed in Qt 6.0.
+
Bearer Management controls the connectivity state of the system so that
the user can start or stop interfaces or roam transparently between
access points.
diff --git a/src/network/doc/src/qtnetwork.qdoc b/src/network/doc/src/qtnetwork.qdoc
index 85a3c198a0..57b0210b7f 100644
--- a/src/network/doc/src/qtnetwork.qdoc
+++ b/src/network/doc/src/qtnetwork.qdoc
@@ -34,19 +34,16 @@
TCP/IP. Operations such as requests, cookies, and sending data over HTTP
are handled by various C++ classes.
- \section1 Getting Started
+ \include module-use.qdocinc using qt module
+ \snippet CMakeLists.txt 0
- To use Qt Network classes,add this directive into the C++ files:
- \code
- #include <QtNetwork>
- \endcode
+ See also the \l{Build with CMake} overview.
- \if !defined(qtforpython)
- To link against the Qt Network module, add this line to the project file:
- \code
- QT += network
- \endcode
- \endif
+ \section2 Building with qmake
+
+ Add \c network to the \c QT variable:
+
+ \snippet snippets.pro 0
\section1 Articles and Guides
@@ -100,13 +97,6 @@
\qtvariable network
\brief Provides classes to make network programming easier and portable.
- To include the definitions of the module's classes, use the
- following directive:
-
- \snippet code/doc_src_qtnetwork.cpp 1
-
- To link against the module, add this line to your \l qmake \c
- .pro file:
-
- \snippet code/doc_src_qtnetwork.pro 0
+ Qt Network provides a set of APIs for programming applications that use
+ TCP/IP. See the \l{Qt Network} overview for more information.
*/
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index da952f6e6b..aa2f8fed02 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -564,12 +564,12 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
int pos = -1;
#if QT_CONFIG(regularexpression)
- if (syntax == Wildcard)
+ if (syntax == PatternSyntax::Wildcard)
pos = pathPrefix.indexOf(QRegularExpression(QLatin1String("[*?[]")));
- else if (syntax == RegExp)
+ else if (syntax == PatternSyntax::RegularExpression)
pos = sourcePath.indexOf(QRegularExpression(QLatin1String("[\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
#else
- if (syntax == Wildcard || syntax == RegExp)
+ if (syntax == PatternSyntax::Wildcard || syntax == PatternSyntax::RegExp)
qWarning("Regular expression support is disabled in this build. Only fixed string can be searched");
return QList<QSslCertificate>();
#endif
@@ -606,7 +606,7 @@ QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
QList<QSslCertificate> certs;
#if QT_CONFIG(regularexpression)
- if (syntax == Wildcard)
+ if (syntax == PatternSyntax::Wildcard)
sourcePath = QRegularExpression::wildcardToRegularExpression(sourcePath);
QRegularExpression pattern(QRegularExpression::anchoredPattern(sourcePath));
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
index c46065160a..525642a809 100644
--- a/src/network/ssl/qsslcertificate.h
+++ b/src/network/ssl/qsslcertificate.h
@@ -84,8 +84,8 @@ public:
EmailAddress
};
- enum PatternSyntax {
- RegExp,
+ enum class PatternSyntax {
+ RegularExpression,
Wildcard,
FixedString
};
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
index 5732deaaef..1ce01dbee9 100644
--- a/src/network/ssl/qsslconfiguration.h
+++ b/src/network/ssl/qsslconfiguration.h
@@ -130,8 +130,9 @@ public:
// Certificate Authority (CA) settings
QList<QSslCertificate> caCertificates() const;
void setCaCertificates(const QList<QSslCertificate> &certificates);
- bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
- QSslCertificate::PatternSyntax syntax = QSslCertificate::FixedString);
+ bool addCaCertificates(
+ const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
+ QSslCertificate::PatternSyntax syntax = QSslCertificate::PatternSyntax::FixedString);
void addCaCertificate(const QSslCertificate &certificate);
void addCaCertificates(const QList<QSslCertificate> &certificates);
diff --git a/src/network/ssl/qsslsocket_schannel.cpp b/src/network/ssl/qsslsocket_schannel.cpp
index 2db5c48ff2..c355abad73 100644
--- a/src/network/ssl/qsslsocket_schannel.cpp
+++ b/src/network/ssl/qsslsocket_schannel.cpp
@@ -1306,7 +1306,8 @@ void QSslSocketBackendPrivate::transmit()
int totalRead = 0;
bool hadIncompleteData = false;
while (!readBufferMaxSize || buffer.size() < readBufferMaxSize) {
- if (missingData > plainSocket->bytesAvailable()) {
+ if (missingData > plainSocket->bytesAvailable()
+ && (!readBufferMaxSize || readBufferMaxSize >= missingData)) {
#ifdef QSSLSOCKET_DEBUG
qCDebug(lcSsl, "We're still missing %lld bytes, will check later.", missingData);
#endif
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index d7ccd9db92..d38fa299f9 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -48,6 +48,7 @@
#include <qscreen.h>
#include <qpa/qplatformscreen.h>
#include <QtCore/QUuid>
+#include <QtGui/QPainterPath>
#ifndef QT_NO_FREETYPE
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index ce793dfafa..115b13d60d 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -45,6 +45,7 @@
#include <QtCore/qsettings.h>
#endif
#include <QtCore/qoperatingsystemversion.h>
+#include <QtGui/qpainterpath.h>
#include <private/qcoregraphics_p.h>
#include <private/qimage_p.h>
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
index b11ad46bc7..4e6b22ce94 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
@@ -51,6 +51,7 @@
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtGui/qpainterpath.h>
#if defined(QT_USE_DIRECTWRITE2)
# include <dwrite_2.h>
diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp
index 734bdcaf75..b583d636c0 100644
--- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp
+++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp
@@ -166,7 +166,12 @@ static inline bool launch(const QString &launcher, const QUrl &url)
#if !QT_CONFIG(process)
const bool ok = ::system(qPrintable(command + QLatin1String(" &")));
#else
- const bool ok = QProcess::startDetached(command);
+ QStringList args = QProcess::splitCommand(command);
+ bool ok = false;
+ if (!args.isEmpty()) {
+ QString program = args.takeFirst();
+ ok = QProcess::startDetached(program, args);
+ }
#endif
if (!ok)
qWarning("Launch failed (%s)", qPrintable(command));
diff --git a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp
index 79541fe636..8038e1a3c3 100644
--- a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp
+++ b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper.cpp
@@ -53,6 +53,7 @@ QWindowsUiaWrapper::QWindowsUiaWrapper()
m_pUiaHostProviderFromHwnd = reinterpret_cast<PtrUiaHostProviderFromHwnd>(uiaLib.resolve("UiaHostProviderFromHwnd"));
m_pUiaRaiseAutomationPropertyChangedEvent = reinterpret_cast<PtrUiaRaiseAutomationPropertyChangedEvent>(uiaLib.resolve("UiaRaiseAutomationPropertyChangedEvent"));
m_pUiaRaiseAutomationEvent = reinterpret_cast<PtrUiaRaiseAutomationEvent>(uiaLib.resolve("UiaRaiseAutomationEvent"));
+ m_pUiaRaiseNotificationEvent = reinterpret_cast<PtrUiaRaiseNotificationEvent>(uiaLib.resolve("UiaRaiseNotificationEvent"));
m_pUiaClientsAreListening = reinterpret_cast<PtrUiaClientsAreListening>(uiaLib.resolve("UiaClientsAreListening"));
}
}
@@ -68,7 +69,7 @@ QWindowsUiaWrapper *QWindowsUiaWrapper::instance()
return &wrapper;
}
-// True if all symbols resolved.
+// True if most symbols resolved (UiaRaiseNotificationEvent is optional).
BOOL QWindowsUiaWrapper::ready()
{
return m_pUiaReturnRawElementProvider
@@ -113,5 +114,12 @@ HRESULT QWindowsUiaWrapper::raiseAutomationEvent(IRawElementProviderSimple *pPro
return m_pUiaRaiseAutomationEvent(pProvider, id);
}
+HRESULT QWindowsUiaWrapper::raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId)
+{
+ if (!m_pUiaRaiseNotificationEvent)
+ return UIA_E_NOTSUPPORTED;
+ return m_pUiaRaiseNotificationEvent(provider, notificationKind, notificationProcessing, displayString, activityId);
+}
+
QT_END_NAMESPACE
diff --git a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h
index 3ebc3008d3..9208acbc31 100644
--- a/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h
+++ b/src/platformsupport/windowsuiautomation/qwindowsuiawrapper_p.h
@@ -80,17 +80,20 @@ public:
HRESULT hostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **ppProvider);
HRESULT raiseAutomationPropertyChangedEvent(IRawElementProviderSimple *pProvider, PROPERTYID id, VARIANT oldValue, VARIANT newValue);
HRESULT raiseAutomationEvent(IRawElementProviderSimple *pProvider, EVENTID id);
+ HRESULT raiseNotificationEvent(IRawElementProviderSimple *provider, NotificationKind notificationKind, NotificationProcessing notificationProcessing, BSTR displayString, BSTR activityId);
private:
typedef LRESULT (WINAPI *PtrUiaReturnRawElementProvider)(HWND, WPARAM, LPARAM, IRawElementProviderSimple *);
typedef HRESULT (WINAPI *PtrUiaHostProviderFromHwnd)(HWND, IRawElementProviderSimple **);
typedef HRESULT (WINAPI *PtrUiaRaiseAutomationPropertyChangedEvent)(IRawElementProviderSimple *, PROPERTYID, VARIANT, VARIANT);
typedef HRESULT (WINAPI *PtrUiaRaiseAutomationEvent)(IRawElementProviderSimple *, EVENTID);
+ typedef HRESULT (WINAPI *PtrUiaRaiseNotificationEvent)(IRawElementProviderSimple *, NotificationKind, NotificationProcessing, BSTR, BSTR);
typedef BOOL (WINAPI *PtrUiaClientsAreListening)();
PtrUiaReturnRawElementProvider m_pUiaReturnRawElementProvider = nullptr;
PtrUiaHostProviderFromHwnd m_pUiaHostProviderFromHwnd = nullptr;
PtrUiaRaiseAutomationPropertyChangedEvent m_pUiaRaiseAutomationPropertyChangedEvent = nullptr;
PtrUiaRaiseAutomationEvent m_pUiaRaiseAutomationEvent = nullptr;
+ PtrUiaRaiseNotificationEvent m_pUiaRaiseNotificationEvent = nullptr;
PtrUiaClientsAreListening m_pUiaClientsAreListening = nullptr;
};
diff --git a/src/platformsupport/windowsuiautomation/uiatypes_p.h b/src/platformsupport/windowsuiautomation/uiatypes_p.h
index afbc957094..0d2e1161e4 100644
--- a/src/platformsupport/windowsuiautomation/uiatypes_p.h
+++ b/src/platformsupport/windowsuiautomation/uiatypes_p.h
@@ -162,6 +162,22 @@ enum ExpandCollapseState {
ExpandCollapseState_LeafNode = 3
};
+enum NotificationKind {
+ NotificationKind_ItemAdded = 0,
+ NotificationKind_ItemRemoved = 1,
+ NotificationKind_ActionCompleted = 2,
+ NotificationKind_ActionAborted = 3,
+ NotificationKind_Other = 4
+};
+
+enum NotificationProcessing {
+ NotificationProcessing_ImportantAll = 0,
+ NotificationProcessing_ImportantMostRecent = 1,
+ NotificationProcessing_All = 2,
+ NotificationProcessing_MostRecent = 3,
+ NotificationProcessing_CurrentThenMostRecent = 4
+};
+
struct UiaRect {
double left;
double top;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 28da4fcf5d..61bf0d4a4e 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -1632,6 +1632,7 @@ QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)
nsWindow.restorable = NO;
nsWindow.level = windowLevel(flags);
+ nsWindow.tabbingMode = NSWindowTabbingModeDisallowed;
if (shouldBePanel) {
// Qt::Tool windows hide on app deactivation, unless Qt::WA_MacAlwaysShowToolWindow is set
diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
index 9adc5c78dd..59360616a1 100644
--- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
+++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp
@@ -166,11 +166,27 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
}
if (event->value().type() == QVariant::String) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
- // Notifies changes in string values.
- VARIANT oldVal, newVal;
- clearVariant(&oldVal);
- setVariantString(event->value().toString(), &newVal);
- QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
+
+ // Tries to notify the change using UiaRaiseNotificationEvent(), which is only available on
+ // Windows 10 version 1709 or newer. Otherwise uses UiaRaiseAutomationPropertyChangedEvent().
+
+ BSTR displayString = bStrFromQString(event->value().toString());
+ BSTR activityId = bStrFromQString(QString());
+
+ HRESULT hr = QWindowsUiaWrapper::instance()->raiseNotificationEvent(provider, NotificationKind_Other,
+ NotificationProcessing_ImportantMostRecent,
+ displayString, activityId);
+
+ ::SysFreeString(displayString);
+ ::SysFreeString(activityId);
+
+ if (hr == static_cast<HRESULT>(UIA_E_NOTSUPPORTED)) {
+ VARIANT oldVal, newVal;
+ clearVariant(&oldVal);
+ setVariantString(event->value().toString(), &newVal);
+ QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
+ ::SysFreeString(newVal.bstrVal);
+ }
}
} else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
diff --git a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
index 114d6dacd8..fee8063f13 100644
--- a/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfiledialoghelper.cpp
@@ -397,7 +397,15 @@ bool QWinRTFileDialogHelper::show(Qt::WindowFlags windowFlags, Qt::WindowModalit
RETURN_FALSE_IF_FAILED_WITH_ARGS("Failed to set default file extension \"%s\"", qPrintable(suffix));
}
- const QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName();
+ QString suggestedName = QFileInfo(d->saveFileName.toLocalFile()).fileName();
+ if (suggestedName.isEmpty() && dialogOptions->initiallySelectedFiles().size() > 0)
+ suggestedName = QFileInfo(dialogOptions->initiallySelectedFiles().first().toLocalFile())
+ .fileName();
+ if (suggestedName.isEmpty()) {
+ const auto fileInfo = QFileInfo(dialogOptions->initialDirectory().toLocalFile());
+ if (!fileInfo.isDir())
+ suggestedName = fileInfo.fileName();
+ }
if (!suggestedName.isEmpty()) {
HStringReference nativeSuggestedName(reinterpret_cast<const wchar_t *>(suggestedName.utf16()),
uint(suggestedName.length()));
diff --git a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
index be1a06bc1d..2f56487f88 100644
--- a/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
+++ b/src/plugins/sqldrivers/odbc/qsql_odbc.cpp
@@ -2379,7 +2379,7 @@ QStringList QODBCDriver::tables(QSql::TableType type) const
}
while (r == SQL_SUCCESS) {
- QString fieldVal = qGetStringData(hStmt, 2, -1, false);
+ QString fieldVal = qGetStringData(hStmt, 2, -1, d->unicode);
tl.append(fieldVal);
if (d->hasSQLFetchScroll)
diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm
index f473c3cbe3..f8e423456f 100644
--- a/src/plugins/styles/mac/qmacstyle_mac.mm
+++ b/src/plugins/styles/mac/qmacstyle_mac.mm
@@ -56,6 +56,7 @@
#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qpa/qplatformfontdatabase.h>
#include <QtGui/qpa/qplatformtheme.h>
diff --git a/src/printsupport/dialogs/qprintdialog_mac.mm b/src/printsupport/dialogs/qprintdialog_mac.mm
index ed2d0908c4..a4101f7ec0 100644
--- a/src/printsupport/dialogs/qprintdialog_mac.mm
+++ b/src/printsupport/dialogs/qprintdialog_mac.mm
@@ -42,6 +42,7 @@
#include "qprintdialog.h"
#include "qabstractprintdialog_p.h"
+#include <QtCore/qtemporarydir.h>
#include <QtCore/private/qcore_mac_p.h>
#include <QtWidgets/private/qapplication_p.h>
#include <QtPrintSupport/qprinter.h>
@@ -127,21 +128,36 @@ QT_USE_NAMESPACE
PMDestinationType dest;
PMSessionGetDestinationType(session, settings, &dest);
if (dest == kPMDestinationFile) {
- // QTBUG-38820
- // If user selected Print to File, leave OSX to generate the PDF,
- // otherwise setting PdfFormat would prevent us showing dialog again.
- // TODO Restore this when QTBUG-36112 is fixed.
- /*
QCFType<CFURLRef> file;
PMSessionCopyDestinationLocation(session, settings, &file);
UInt8 localFile[2048]; // Assuming there's a POSIX file system here.
CFURLGetFileSystemRepresentation(file, true, localFile, sizeof(localFile));
- printer->setOutputFileName(QString::fromUtf8(reinterpret_cast<const char *>(localFile)));
- */
- } else {
+ auto outputFile = QFileInfo(QString::fromUtf8(reinterpret_cast<const char *>(localFile)));
+ if (outputFile.suffix() == QLatin1String("pdf"))
+ printer->setOutputFileName(outputFile.absoluteFilePath());
+ else
+ qWarning() << "Can not print to file type" << outputFile.suffix();
+ } else if (dest == kPMDestinationPreview) {
+ static QTemporaryDir printPreviews;
+ auto documentName = printer->docName();
+ if (documentName.isEmpty())
+ documentName = QGuiApplication::applicationDisplayName();
+ auto fileName = printPreviews.filePath(QString(QLatin1String("%1.pdf")).arg(documentName));
+ printer->setOutputFileName(fileName);
+ // Ideally we would have a callback when the PDF engine is done writing
+ // to the file, and open Preview in response to that. Lacking that, we
+ // use the quick and dirty assumption that the the print operation will
+ // happen synchronously after the dialog is accepted, so we can defer
+ // the opening of the file to the next runloop pass.
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [NSWorkspace.sharedWorkspace openFile:fileName.toNSString()];
+ });
+ } else if (dest == kPMDestinationProcessPDF) {
+ qWarning("Printing workflows are not supported");
+ } else if (dest == kPMDestinationPrinter) {
PMPrinter macPrinter;
PMSessionGetCurrentPrinter(session, &macPrinter);
- QString printerId = QString::fromCFString(PMPrinterGetID(macPrinter));
+ QString printerId = QString::fromCFString(PMPrinterGetID(macPrinter)).trimmed();
if (printer->printerName() != printerId)
printer->setPrinterName(printerId);
}
@@ -199,14 +215,18 @@ void QPrintDialogPrivate::openCocoaPrintPanel(Qt::WindowModality modality)
{
Q_Q(QPrintDialog);
- // get the NSPrintInfo from the print engine in the platform plugin
- void *voidp = 0;
- (void) QMetaObject::invokeMethod(qApp->platformNativeInterface(),
- "NSPrintInfoForPrintEngine",
- Q_RETURN_ARG(void *, voidp),
- Q_ARG(QPrintEngine *, printer->printEngine()));
- printInfo = static_cast<NSPrintInfo *>(voidp);
- [printInfo retain];
+ if (printer->outputFormat() == QPrinter::NativeFormat) {
+ // get the NSPrintInfo from the print engine in the platform plugin
+ void *voidp = 0;
+ (void) QMetaObject::invokeMethod(qApp->platformNativeInterface(),
+ "NSPrintInfoForPrintEngine",
+ Q_RETURN_ARG(void *, voidp),
+ Q_ARG(QPrintEngine *, printer->printEngine()));
+ printInfo = static_cast<NSPrintInfo *>(voidp);
+ [printInfo retain];
+ } else {
+ printInfo = [NSPrintInfo.sharedPrintInfo retain];
+ }
// It seems the only way that PM lets you use all is if the minimum
// for the page range is 1. This _kind of_ makes sense if you think about
@@ -269,31 +289,15 @@ void QPrintDialogPrivate::closeCocoaPrintPanel()
printPanel = 0;
}
-static bool warnIfNotNative(QPrinter *printer)
-{
- if (printer->outputFormat() != QPrinter::NativeFormat) {
- qWarning("QPrintDialog: Cannot be used on non-native printers");
- return false;
- }
- return true;
-}
-
-
QPrintDialog::QPrintDialog(QPrinter *printer, QWidget *parent)
: QAbstractPrintDialog(*(new QPrintDialogPrivate), printer, parent)
{
- Q_D(QPrintDialog);
- if (!warnIfNotNative(d->printer))
- return;
setAttribute(Qt::WA_DontShowOnScreen);
}
QPrintDialog::QPrintDialog(QWidget *parent)
: QAbstractPrintDialog(*(new QPrintDialogPrivate), 0, parent)
{
- Q_D(QPrintDialog);
- if (!warnIfNotNative(d->printer))
- return;
setAttribute(Qt::WA_DontShowOnScreen);
}
@@ -304,8 +308,6 @@ QPrintDialog::~QPrintDialog()
int QPrintDialog::exec()
{
Q_D(QPrintDialog);
- if (!warnIfNotNative(d->printer))
- return QDialog::Rejected;
QDialog::setVisible(true);
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index bcb96841df..ba3c0dad83 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -170,6 +170,8 @@ struct Options
// Versioning
QString versionName;
QString versionCode;
+ QByteArray minSdkVersion{"21"};
+ QByteArray targetSdkVersion{"28"};
// lib c++ path
QString stdCppPath;
@@ -860,6 +862,18 @@ bool readInputFile(Options *options)
}
{
+ const QJsonValue ver = jsonObject.value(QLatin1String("android-min-sdk-version"));
+ if (!ver.isUndefined())
+ options->minSdkVersion = ver.toString().toUtf8();
+ }
+
+ {
+ const QJsonValue ver = jsonObject.value(QLatin1String("android-target-sdk-version"));
+ if (!ver.isUndefined())
+ options->targetSdkVersion = ver.toString().toUtf8();
+ }
+
+ {
const QJsonObject targetArchitectures = jsonObject.value(QLatin1String("architectures")).toObject();
if (targetArchitectures.isEmpty()) {
fprintf(stderr, "No target architecture defined in json file.\n");
@@ -2319,6 +2333,8 @@ bool buildAndroidProject(const Options &options)
gradleProperties["buildDir"] = "build";
gradleProperties["qt5AndroidDir"] = (options.qtInstallDirectory + QLatin1String("/src/android/java")).toUtf8();
gradleProperties["androidCompileSdkVersion"] = options.androidPlatform.split(QLatin1Char('-')).last().toLocal8Bit();
+ gradleProperties["qtMinSdkVersion"] = options.minSdkVersion;
+ gradleProperties["qtTargetSdkVersion"] = options.targetSdkVersion;
if (gradleProperties["androidBuildToolsVersion"].isEmpty())
gradleProperties["androidBuildToolsVersion"] = options.sdkBuildToolsVersion.toLocal8Bit();
diff --git a/src/widgets/graphicsview/qgraphicsscene.cpp b/src/widgets/graphicsview/qgraphicsscene.cpp
index bbcceb1ce6..b669b0fe61 100644
--- a/src/widgets/graphicsview/qgraphicsscene.cpp
+++ b/src/widgets/graphicsview/qgraphicsscene.cpp
@@ -233,6 +233,7 @@
#include <QtWidgets/qgraphicswidget.h>
#include <QtGui/qpaintengine.h>
#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/qpixmapcache.h>
#include <QtGui/qpolygon.h>
#include <QtGui/qtouchdevice.h>
diff --git a/src/widgets/graphicsview/qgraphicssceneindex.cpp b/src/widgets/graphicsview/qgraphicssceneindex.cpp
index c2e9cb4729..aab9068374 100644
--- a/src/widgets/graphicsview/qgraphicssceneindex.cpp
+++ b/src/widgets/graphicsview/qgraphicssceneindex.cpp
@@ -60,6 +60,7 @@
#include "qgraphicswidget.h"
#include "qgraphicssceneindex_p.h"
#include "qgraphicsscenebsptreeindex_p.h"
+#include <QtGui/qpainterpath.h>
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/graphicsview/qgraphicsview.cpp b/src/widgets/graphicsview/qgraphicsview.cpp
index a744847f33..1117f5e473 100644
--- a/src/widgets/graphicsview/qgraphicsview.cpp
+++ b/src/widgets/graphicsview/qgraphicsview.cpp
@@ -293,6 +293,7 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime <
#include <QtWidgets/qlayout.h>
#include <QtGui/qtransform.h>
#include <QtGui/qpainter.h>
+#include <QtGui/qpainterpath.h>
#include <QtWidgets/qscrollbar.h>
#include <QtWidgets/qstyleoption.h>
diff --git a/src/widgets/graphicsview/qgraphicswidget.cpp b/src/widgets/graphicsview/qgraphicswidget.cpp
index 6242314e1d..472d61d437 100644
--- a/src/widgets/graphicsview/qgraphicswidget.cpp
+++ b/src/widgets/graphicsview/qgraphicswidget.cpp
@@ -59,6 +59,7 @@
#include <QtWidgets/qgraphicsview.h>
#include <QtWidgets/qgraphicsproxywidget.h>
#include <QtGui/qpalette.h>
+#include <QtGui/qpainterpath.h>
#include <QtWidgets/qstyleoption.h>
#include <qdebug.h>
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 4b0094e578..45ac6712b4 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -6125,7 +6125,7 @@ QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption
const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size.width());
if (standardIcon >= QStyle::SP_CustomBase) {
mainIcon = theme->standardPixmap(sp, QSizeF(size));
- } else if (QPixmapCache::find(cacheKey, mainIcon) == false) {
+ } else if (QPixmapCache::find(cacheKey, &mainIcon) == false) {
mainIcon = theme->standardPixmap(sp, QSizeF(size));
QPixmapCache::insert(cacheKey, mainIcon);
}
diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp
index 4427d69944..2a0d6d1b40 100644
--- a/src/widgets/styles/qfusionstyle.cpp
+++ b/src/widgets/styles/qfusionstyle.cpp
@@ -52,6 +52,7 @@
#include <qabstractbutton.h>
#endif
#include <qpainter.h>
+#include <qpainterpath.h>
#include <qdir.h>
#include <qstyleoption.h>
#include <qapplication.h>
diff --git a/src/widgets/styles/qstylesheetstyle.cpp b/src/widgets/styles/qstylesheetstyle.cpp
index 1e032b237a..b07abe4f51 100644
--- a/src/widgets/styles/qstylesheetstyle.cpp
+++ b/src/widgets/styles/qstylesheetstyle.cpp
@@ -118,6 +118,7 @@
#include <QtWidgets/qtoolbar.h>
#endif
+#include <QtGui/qpainterpath.h>
#include <QtGui/qscreen.h>
QT_BEGIN_NAMESPACE
diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp
index 4965d146b0..e275e3a714 100644
--- a/src/widgets/styles/qwindowsstyle.cpp
+++ b/src/widgets/styles/qwindowsstyle.cpp
@@ -78,6 +78,7 @@
#endif
#include <private/qmath_p.h>
#include <qmath.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/qscreen.h>
#include <QtGui/qwindow.h>
#include <qpa/qplatformtheme.h>
diff --git a/tests/auto/corelib/io/qloggingregistry/tst_qloggingregistry.cpp b/tests/auto/corelib/io/qloggingregistry/tst_qloggingregistry.cpp
index a10e706ed7..4c269822d6 100644
--- a/tests/auto/corelib/io/qloggingregistry/tst_qloggingregistry.cpp
+++ b/tests/auto/corelib/io/qloggingregistry/tst_qloggingregistry.cpp
@@ -158,10 +158,13 @@ private slots:
QFETCH(QtMsgType, msgType);
QFETCH(LoggingRuleState, result);
- QLoggingRule rule(QStringRef(&pattern), true);
+ const auto categoryL1 = category.toLatin1();
+ const auto categoryL1S = QLatin1String(categoryL1);
+
+ QLoggingRule rule(pattern, true);
LoggingRuleState state = Invalid;
if (rule.flags != 0) {
- switch (rule.pass(category, msgType)) {
+ switch (rule.pass(categoryL1S, msgType)) {
case -1: QFAIL("Shoudn't happen, we set pattern to true"); break;
case 0: state = NoMatch; break;
case 1: state = Match; break;
diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
index 5fc4343cd9..419a8138a1 100644
--- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
@@ -28,12 +28,13 @@
#include <QtTest/QtTest>
#include <QtGui/QBitmap>
+#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
#include <QtGui/QPalette>
-#include <QtGui/QPixmap>
+#include <QtGui/QPen>
#include <QtGui/QPicture>
+#include <QtGui/QPixmap>
#include <QtGui/QTextLength>
-#include <QtGui/QPainter>
-#include <QtGui/QPen>
class tst_QDataStream : public QObject
{
diff --git a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp
index bcf4e73108..35546c2968 100644
--- a/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp
+++ b/tests/auto/corelib/text/qstringapisymmetry/tst_qstringapisymmetry.cpp
@@ -73,6 +73,8 @@ QStringList toQStringList(const Iterable &i) {
MAKE_ALL(QByteArray, QChar)
MAKE_ALL(QByteArray, QLatin1String)
+MAKE_ALL(QByteArray, char16_t)
+MAKE_ALL(char16_t, QByteArray)
MAKE_ALL(const char*, QChar)
@@ -100,6 +102,11 @@ static QByteArray rowName(const QByteArray &data)
return result;
}
+# define QVERIFY_NOEXCEPT(expr) do { \
+ if (!has_nothrow_compare<LHS, RHS>::value) \
+ QEXPECT_FAIL("", "Qt is missing a nothrow utf8-utf16 comparator", Continue); \
+ QVERIFY(noexcept(expr)); } while (0)
+
class tst_QStringApiSymmetry : public QObject
{
Q_OBJECT
@@ -113,9 +120,11 @@ class tst_QStringApiSymmetry : public QObject
void compare_impl() const;
private Q_SLOTS:
- // test all combinations of {QChar, QStringRef, QString, QStringView, QLatin1String, QByteArray, const char*}
+ // test all combinations of {QChar, char16_t, QStringRef, QString, QStringView, QLatin1String, QByteArray, const char*}
void compare_QChar_QChar_data() { compare_data(false); }
void compare_QChar_QChar() { compare_impl<QChar, QChar>(); }
+ void compare_QChar_char16_t_data() { compare_data(false); }
+ void compare_QChar_char16_t() { compare_impl<QChar, char16_t>(); }
void compare_QChar_QStringRef_data() { compare_data(false); }
void compare_QChar_QStringRef() { compare_impl<QChar, QStringRef>(); }
void compare_QChar_QString_data() { compare_data(false); }
@@ -129,8 +138,27 @@ private Q_SLOTS:
void compare_QChar_const_char_star_data() { compare_data(false); }
void compare_QChar_const_char_star() { compare_impl<QChar, const char *>(); }
+ void compare_char16_t_QChar_data() { compare_data(false); }
+ void compare_char16_t_QChar() { compare_impl<char16_t, QChar>(); }
+ //void compare_char16_t_char16_t_data() { compare_data(false); }
+ //void compare_char16_t_char16_t() { compare_impl<char16_t, char16_t>(); }
+ void compare_char16_t_QStringRef_data() { compare_data(false); }
+ void compare_char16_t_QStringRef() { compare_impl<char16_t, QStringRef>(); }
+ void compare_char16_t_QString_data() { compare_data(false); }
+ void compare_char16_t_QString() { compare_impl<char16_t, QString>(); }
+ void compare_char16_t_QStringView_data() { compare_data(false); }
+ void compare_char16_t_QStringView() { compare_impl<char16_t, QStringView>(); }
+ void compare_char16_t_QLatin1String_data() { compare_data(false); }
+ void compare_char16_t_QLatin1String() { compare_impl<char16_t, QLatin1String>(); }
+ void compare_char16_t_QByteArray_data() { compare_data(false); }
+ void compare_char16_t_QByteArray() { compare_impl<char16_t, QByteArray>(); }
+ //void compare_char16_t_const_char_star_data() { compare_data(false); }
+ //void compare_char16_t_const_char_star() { compare_impl<char16_t, const char *>(); }
+
void compare_QStringRef_QChar_data() { compare_data(false); }
void compare_QStringRef_QChar() { compare_impl<QStringRef, QChar>(); }
+ void compare_QStringRef_char16_t_data() { compare_data(false); }
+ void compare_QStringRef_char16_t() { compare_impl<QStringRef, char16_t>(); }
void compare_QStringRef_QStringRef_data() { compare_data(); }
void compare_QStringRef_QStringRef() { compare_impl<QStringRef, QStringRef>(); }
void compare_QStringRef_QString_data() { compare_data(); }
@@ -146,6 +174,8 @@ private Q_SLOTS:
void compare_QString_QChar_data() { compare_data(false); }
void compare_QString_QChar() { compare_impl<QString, QChar>(); }
+ void compare_QString_char16_t_data() { compare_data(false); }
+ void compare_QString_char16_t() { compare_impl<QString, char16_t>(); }
void compare_QString_QStringRef_data() { compare_data(); }
void compare_QString_QStringRef() { compare_impl<QString, QStringRef>(); }
void compare_QString_QString_data() { compare_data(); }
@@ -161,6 +191,8 @@ private Q_SLOTS:
void compare_QStringView_QChar_data() { compare_data(false); }
void compare_QStringView_QChar() { compare_impl<QStringView, QChar>(); }
+ void compare_QStringView_char16_t_data() { compare_data(false); }
+ void compare_QStringView_char16_t() { compare_impl<QStringView, char16_t>(); }
void compare_QStringView_QStringRef_data() { compare_data(); }
void compare_QStringView_QStringRef() { compare_impl<QStringView, QStringRef>(); }
void compare_QStringView_QString_data() { compare_data(); }
@@ -178,6 +210,8 @@ private Q_SLOTS:
void compare_QLatin1String_QChar_data() { compare_data(false); }
void compare_QLatin1String_QChar() { compare_impl<QLatin1String, QChar>(); }
+ void compare_QLatin1String_char16_t_data() { compare_data(false); }
+ void compare_QLatin1String_char16_t() { compare_impl<QLatin1String, char16_t>(); }
void compare_QLatin1String_QStringRef_data() { compare_data(); }
void compare_QLatin1String_QStringRef() { compare_impl<QLatin1String, QStringRef>(); }
void compare_QLatin1String_QString_data() { compare_data(); }
@@ -193,6 +227,8 @@ private Q_SLOTS:
void compare_QByteArray_QChar_data() { compare_data(false); }
void compare_QByteArray_QChar() { compare_impl<QByteArray, QChar>(); }
+ void compare_QByteArray_char16_t_data() { compare_data(false); }
+ void compare_QByteArray_char16_t() { compare_impl<QByteArray, char16_t>(); }
void compare_QByteArray_QStringRef_data() { compare_data(); }
void compare_QByteArray_QStringRef() { compare_impl<QByteArray, QStringRef>(); }
void compare_QByteArray_QString_data() { compare_data(); }
@@ -206,6 +242,8 @@ private Q_SLOTS:
void compare_const_char_star_QChar_data() { compare_data(false); }
void compare_const_char_star_QChar() { compare_impl<const char *, QChar>(); }
+ //void compare_const_char_star_char16_t_data() { compare_data(false); }
+ //void compare_const_char_star_char16_t() { compare_impl<const char *, char16_t>(); }
void compare_const_char_star_QStringRef_data() { compare_data(); }
void compare_const_char_star_QStringRef() { compare_impl<const char *, QStringRef>(); }
void compare_const_char_star_QString_data() { compare_data(); }
@@ -223,10 +261,12 @@ private:
void member_compare_impl() const;
private Q_SLOTS:
- // test all combinations of {QChar, QStringRef, QString, QStringView, QLatin1String, QByteArray, const char*}
+ // test all combinations of {QChar, char16_t, QStringRef, QString, QStringView, QLatin1String, QByteArray, const char*}
#ifdef NOT_YET_IMPLEMENTED // probably never will be - what's the point of QChar::compare(QStringView)?
void member_compare_QChar_QChar_data() { member_compare_data(false); }
void member_compare_QChar_QChar() { member_compare_impl<QChar, QChar>(); }
+ void member_compare_QChar_char16_t_data() { member_compare_data(false); }
+ void member_compare_QChar_char16_t() { member_compare_impl<QChar, char16_t>(); }
void member_compare_QChar_QStringRef_data() { member_compare_data(false); }
void member_compare_QChar_QStringRef() { member_compare_impl<QChar, QStringRef>(); }
void member_compare_QChar_QString_data() { member_compare_data(false); }
@@ -241,8 +281,12 @@ private Q_SLOTS:
void member_compare_QChar_const_char_star() { member_compare_impl<QChar, const char *>(); }
#endif
+ // void member_compare_char16_t_XXX() - not possible
+
void member_compare_QStringRef_QChar_data() { member_compare_data(false); }
void member_compare_QStringRef_QChar() { member_compare_impl<QStringRef, QChar>(); }
+ void member_compare_QStringRef_char16_t_data() { member_compare_data(false); }
+ void member_compare_QStringRef_char16_t() { member_compare_impl<QStringRef, char16_t>(); }
void member_compare_QStringRef_QStringRef_data() { member_compare_data(); }
void member_compare_QStringRef_QStringRef() { member_compare_impl<QStringRef, QStringRef>(); }
void member_compare_QStringRef_QString_data() { member_compare_data(); }
@@ -262,6 +306,8 @@ private Q_SLOTS:
void member_compare_QString_QChar_data() { member_compare_data(false); }
void member_compare_QString_QChar() { member_compare_impl<QString, QChar>(); }
+ void member_compare_QString_char16_t_data() { member_compare_data(false); }
+ void member_compare_QString_char16_t() { member_compare_impl<QString, char16_t>(); }
void member_compare_QString_QStringRef_data() { member_compare_data(); }
void member_compare_QString_QStringRef() { member_compare_impl<QString, QStringRef>(); }
void member_compare_QString_QString_data() { member_compare_data(); }
@@ -275,26 +321,29 @@ private Q_SLOTS:
void member_compare_QString_const_char_star_data() { member_compare_data(); }
void member_compare_QString_const_char_star() { member_compare_impl<QString, const char *>(); }
-#ifdef NOT_YET_IMPLEMENTED // QChar doesn't implicitly convert to QStringView
void member_compare_QStringView_QChar_data() { member_compare_data(false); }
void member_compare_QStringView_QChar() { member_compare_impl<QStringView, QChar>(); }
-#endif
+ void member_compare_QStringView_char16_t_data() { member_compare_data(false); }
+ void member_compare_QStringView_char16_t() { member_compare_impl<QStringView, char16_t>(); }
void member_compare_QStringView_QStringRef_data() { member_compare_data(); }
void member_compare_QStringView_QStringRef() { member_compare_impl<QStringView, QStringRef>(); }
void member_compare_QStringView_QString_data() { member_compare_data(); }
void member_compare_QStringView_QString() { member_compare_impl<QStringView, QString>(); }
void member_compare_QStringView_QStringView_data() { member_compare_data(); }
void member_compare_QStringView_QStringView() { member_compare_impl<QStringView, QStringView>(); }
-#ifdef NOT_YET_IMPLEMENTED
void member_compare_QStringView_QLatin1String_data() { member_compare_data(); }
void member_compare_QStringView_QLatin1String() { member_compare_impl<QStringView, QLatin1String>(); }
+#ifdef NOT_YET_IMPLEMENTED
void member_compare_QStringView_QByteArray_data() { member_compare_data(); }
void member_compare_QStringView_QByteArray() { member_compare_impl<QStringView, QByteArray>(); }
void member_compare_QStringView_const_char_star_data() { member_compare_data(); }
void member_compare_QStringView_const_char_star() { member_compare_impl<QStringView, const char *>(); }
+#endif
void member_compare_QLatin1String_QChar_data() { member_compare_data(false); }
void member_compare_QLatin1String_QChar() { member_compare_impl<QLatin1String, QChar>(); }
+ void member_compare_QLatin1String_char16_t_data() { member_compare_data(false); }
+ void member_compare_QLatin1String_char16_t() { member_compare_impl<QLatin1String, char16_t>(); }
void member_compare_QLatin1String_QStringRef_data() { member_compare_data(); }
void member_compare_QLatin1String_QStringRef() { member_compare_impl<QLatin1String, QStringRef>(); }
void member_compare_QLatin1String_QString_data() { member_compare_data(); }
@@ -303,6 +352,7 @@ private Q_SLOTS:
void member_compare_QLatin1String_QStringView() { member_compare_impl<QLatin1String, QStringView>(); }
void member_compare_QLatin1String_QLatin1String_data() { member_compare_data(); }
void member_compare_QLatin1String_QLatin1String() { member_compare_impl<QLatin1String, QLatin1String>(); }
+#ifdef NOT_YET_IMPLEMENTED
void member_compare_QLatin1String_QByteArray_data() { member_compare_data(); }
void member_compare_QLatin1String_QByteArray() { member_compare_impl<QLatin1String, QByteArray>(); }
void member_compare_QLatin1String_const_char_star_data() { member_compare_data(); }
@@ -310,6 +360,8 @@ private Q_SLOTS:
void member_compare_QByteArray_QChar_data() { member_compare_data(false); }
void member_compare_QByteArray_QChar() { member_compare_impl<QByteArray, QChar>(); }
+ void member_compare_QByteArray_char16_t_data() { member_compare_data(false); }
+ void member_compare_QByteArray_char16_t() { member_compare_impl<QByteArray, char16_t>(); }
void member_compare_QByteArray_QStringRef_data() { member_compare_data(); }
void member_compare_QByteArray_QStringRef() { member_compare_impl<QByteArray, QStringRef>(); }
void member_compare_QByteArray_QString_data() { member_compare_data(); }
@@ -330,7 +382,7 @@ private:
template <typename Haystack, typename Needle> void endsWith_impl() const;
private Q_SLOTS:
- // test all combinations of {QString, QStringRef, QStringView, QLatin1String} x {QString, QStringRef, QStringView, QLatin1String, QChar}:
+ // test all combinations of {QString, QStringRef, QStringView, QLatin1String} x {QString, QStringRef, QStringView, QLatin1String, QChar, char16_t}:
void startsWith_QString_QString_data() { startsWith_data(); }
void startsWith_QString_QString() { startsWith_impl<QString, QString>(); }
void startsWith_QString_QStringRef_data() { startsWith_data(); }
@@ -341,6 +393,8 @@ private Q_SLOTS:
void startsWith_QString_QLatin1String() { startsWith_impl<QString, QLatin1String>(); }
void startsWith_QString_QChar_data() { startsWith_data(false); }
void startsWith_QString_QChar() { startsWith_impl<QString, QChar>(); }
+ void startsWith_QString_char16_t_data() { startsWith_data(false); }
+ void startsWith_QString_char16_t() { startsWith_impl<QString, char16_t>(); }
void startsWith_QStringRef_QString_data() { startsWith_data(); }
void startsWith_QStringRef_QString() { startsWith_impl<QStringRef, QString>(); }
@@ -352,6 +406,8 @@ private Q_SLOTS:
void startsWith_QStringRef_QLatin1String() { startsWith_impl<QStringRef, QLatin1String>(); }
void startsWith_QStringRef_QChar_data() { startsWith_data(false); }
void startsWith_QStringRef_QChar() { startsWith_impl<QStringRef, QChar>(); }
+ void startsWith_QStringRef_char16_t_data() { startsWith_data(false); }
+ void startsWith_QStringRef_char16_t() { startsWith_impl<QStringRef, char16_t>(); }
void startsWith_QStringView_QString_data() { startsWith_data(); }
void startsWith_QStringView_QString() { startsWith_impl<QStringView, QString>(); }
@@ -363,6 +419,8 @@ private Q_SLOTS:
void startsWith_QStringView_QLatin1String() { startsWith_impl<QStringView, QLatin1String>(); }
void startsWith_QStringView_QChar_data() { startsWith_data(false); }
void startsWith_QStringView_QChar() { startsWith_impl<QStringView, QChar>(); }
+ void startsWith_QStringView_char16_t_data() { startsWith_data(false); }
+ void startsWith_QStringView_char16_t() { startsWith_impl<QStringView, char16_t>(); }
void startsWith_QLatin1String_QString_data() { startsWith_data(); }
void startsWith_QLatin1String_QString() { startsWith_impl<QLatin1String, QString>(); }
@@ -374,6 +432,8 @@ private Q_SLOTS:
void startsWith_QLatin1String_QLatin1String() { startsWith_impl<QLatin1String, QLatin1String>(); }
void startsWith_QLatin1String_QChar_data() { startsWith_data(false); }
void startsWith_QLatin1String_QChar() { startsWith_impl<QLatin1String, QChar>(); }
+ void startsWith_QLatin1String_char16_t_data() { startsWith_data(false); }
+ void startsWith_QLatin1String_char16_t() { startsWith_impl<QLatin1String, char16_t>(); }
void endsWith_QString_QString_data() { endsWith_data(); }
void endsWith_QString_QString() { endsWith_impl<QString, QString>(); }
@@ -385,6 +445,8 @@ private Q_SLOTS:
void endsWith_QString_QLatin1String() { endsWith_impl<QString, QLatin1String>(); }
void endsWith_QString_QChar_data() { endsWith_data(false); }
void endsWith_QString_QChar() { endsWith_impl<QString, QChar>(); }
+ void endsWith_QString_char16_t_data() { endsWith_data(false); }
+ void endsWith_QString_char16_t() { endsWith_impl<QString, char16_t>(); }
void endsWith_QStringRef_QString_data() { endsWith_data(); }
void endsWith_QStringRef_QString() { endsWith_impl<QStringRef, QString>(); }
@@ -396,6 +458,8 @@ private Q_SLOTS:
void endsWith_QStringRef_QLatin1String() { endsWith_impl<QStringRef, QLatin1String>(); }
void endsWith_QStringRef_QChar_data() { endsWith_data(false); }
void endsWith_QStringRef_QChar() { endsWith_impl<QStringRef, QChar>(); }
+ void endsWith_QStringRef_char16_t_data() { endsWith_data(false); }
+ void endsWith_QStringRef_char16_t() { endsWith_impl<QStringRef, char16_t>(); }
void endsWith_QStringView_QString_data() { endsWith_data(); }
void endsWith_QStringView_QString() { endsWith_impl<QStringView, QString>(); }
@@ -407,6 +471,8 @@ private Q_SLOTS:
void endsWith_QStringView_QLatin1String() { endsWith_impl<QStringView, QLatin1String>(); }
void endsWith_QStringView_QChar_data() { endsWith_data(false); }
void endsWith_QStringView_QChar() { endsWith_impl<QStringView, QChar>(); }
+ void endsWith_QStringView_char16_t_data() { endsWith_data(false); }
+ void endsWith_QStringView_char16_t() { endsWith_impl<QStringView, char16_t>(); }
void endsWith_QLatin1String_QString_data() { endsWith_data(); }
void endsWith_QLatin1String_QString() { endsWith_impl<QLatin1String, QString>(); }
@@ -418,6 +484,8 @@ private Q_SLOTS:
void endsWith_QLatin1String_QLatin1String() { endsWith_impl<QLatin1String, QLatin1String>(); }
void endsWith_QLatin1String_QChar_data() { endsWith_data(false); }
void endsWith_QLatin1String_QChar() { endsWith_impl<QLatin1String, QChar>(); }
+ void endsWith_QLatin1String_char16_t_data() { endsWith_data(false); }
+ void endsWith_QLatin1String_char16_t() { endsWith_impl<QLatin1String, char16_t>(); }
private:
void split_data(bool rhsHasVariableLength = true);
@@ -566,9 +634,10 @@ private Q_SLOTS:
private:
template <typename Haystack, typename Needle> void indexOf_impl() const;
- void indexOf_data();
+ void indexOf_data(bool rhsHasVariableLength = true);
private Q_SLOTS:
+ // test all combinations of {QString, QLatin1String, QStringRef, QStringView} x {QString, QLatin1String, QStringRef, QStringView, QChar, char16_t}:
void indexOf_QString_QString_data() { indexOf_data(); }
void indexOf_QString_QString() { indexOf_impl<QString, QString>(); }
void indexOf_QString_QLatin1String_data() { indexOf_data(); }
@@ -577,6 +646,10 @@ private Q_SLOTS:
void indexOf_QString_QStringRef() { indexOf_impl<QString, QStringRef>(); }
void indexOf_QString_QStringView_data() { indexOf_data(); }
void indexOf_QString_QStringView() { indexOf_impl<QString, QStringView>(); }
+ void indexOf_QString_QChar_data() { indexOf_data(false); }
+ void indexOf_QString_QChar() { indexOf_impl<QString, QChar>(); }
+ void indexOf_QString_char16_t_data() { indexOf_data(false); }
+ void indexOf_QString_char16_t() { indexOf_impl<QString, char16_t>(); }
void indexOf_QLatin1String_QString_data() { indexOf_data(); }
void indexOf_QLatin1String_QString() { indexOf_impl<QLatin1String, QString>(); }
@@ -586,6 +659,10 @@ private Q_SLOTS:
void indexOf_QLatin1String_QStringRef() { indexOf_impl<QLatin1String, QStringRef>(); }
void indexOf_QLatin1String_QStringView_data() { indexOf_data(); }
void indexOf_QLatin1String_QStringView() { indexOf_impl<QLatin1String, QStringView>(); }
+ void indexOf_QLatin1String_QChar_data() { indexOf_data(false); }
+ void indexOf_QLatin1String_QChar() { indexOf_impl<QLatin1String, QChar>(); }
+ void indexOf_QLatin1String_char16_t_data() { indexOf_data(false); }
+ void indexOf_QLatin1String_char16_t() { indexOf_impl<QLatin1String, char16_t>(); }
void indexOf_QStringRef_QString_data() { indexOf_data(); }
void indexOf_QStringRef_QString() { indexOf_impl<QStringRef, QString>(); }
@@ -595,6 +672,10 @@ private Q_SLOTS:
void indexOf_QStringRef_QStringRef() { indexOf_impl<QStringRef, QStringRef>(); }
void indexOf_QStringRef_QStringView_data() { indexOf_data(); }
void indexOf_QStringRef_QStringView() { indexOf_impl<QStringRef, QStringView>(); }
+ void indexOf_QStringRef_QChar_data() { indexOf_data(false); }
+ void indexOf_QStringRef_QChar() { indexOf_impl<QStringRef, QChar>(); }
+ void indexOf_QStringRef_char16_t_data() { indexOf_data(false); }
+ void indexOf_QStringRef_char16_t() { indexOf_impl<QStringRef, char16_t>(); }
void indexOf_QStringView_QString_data() { indexOf_data(); }
void indexOf_QStringView_QString() { indexOf_impl<QStringView, QString>(); }
@@ -604,12 +685,17 @@ private Q_SLOTS:
void indexOf_QStringView_QStringRef() { indexOf_impl<QStringView, QStringRef>(); }
void indexOf_QStringView_QStringView_data() { indexOf_data(); }
void indexOf_QStringView_QStringView() { indexOf_impl<QStringView, QStringView>(); }
+ void indexOf_QStringView_QChar_data() { indexOf_data(false); }
+ void indexOf_QStringView_QChar() { indexOf_impl<QStringView, QChar>(); }
+ void indexOf_QStringView_char16_t_data() { indexOf_data(false); }
+ void indexOf_QStringView_char16_t() { indexOf_impl<QStringView, char16_t>(); }
private:
template <typename Haystack, typename Needle> void contains_impl() const;
- void contains_data();
+ void contains_data(bool rhsHasVariableLength = true);
private Q_SLOTS:
+ // test all combinations of {QString, QLatin1String, QStringRef, QStringView} x {QString, QLatin1String, QStringRef, QStringView, QChar, char16_t}:
void contains_QString_QString_data() { contains_data(); }
void contains_QString_QString() { contains_impl<QString, QString>(); }
void contains_QString_QLatin1String_data() { contains_data(); }
@@ -618,6 +704,10 @@ private Q_SLOTS:
void contains_QString_QStringRef() { contains_impl<QString, QStringRef>(); }
void contains_QString_QStringView_data() { contains_data(); }
void contains_QString_QStringView() { contains_impl<QString, QStringView>(); }
+ void contains_QString_QChar_data() { contains_data(false); }
+ void contains_QString_QChar() { contains_impl<QString, QChar>(); }
+ void contains_QString_char16_t_data() { contains_data(false); }
+ void contains_QString_char16_t() { contains_impl<QString, char16_t>(); }
void contains_QLatin1String_QString_data() { contains_data(); }
void contains_QLatin1String_QString() { contains_impl<QLatin1String, QString>(); }
@@ -627,6 +717,10 @@ private Q_SLOTS:
void contains_QLatin1String_QStringRef() { contains_impl<QLatin1String, QStringRef>(); }
void contains_QLatin1String_QStringView_data() { contains_data(); }
void contains_QLatin1String_QStringView() { contains_impl<QLatin1String, QStringView>(); }
+ void contains_QLatin1String_QChar_data() { contains_data(false); }
+ void contains_QLatin1String_QChar() { contains_impl<QLatin1String, QChar>(); }
+ void contains_QLatin1String_char16_t_data() { contains_data(false); }
+ void contains_QLatin1String_char16_t() { contains_impl<QLatin1String, char16_t>(); }
void contains_QStringRef_QString_data() { contains_data(); }
void contains_QStringRef_QString() { contains_impl<QStringRef, QString>(); }
@@ -636,6 +730,10 @@ private Q_SLOTS:
void contains_QStringRef_QStringRef() { contains_impl<QStringRef, QStringRef>(); }
void contains_QStringRef_QStringView_data() { contains_data(); }
void contains_QStringRef_QStringView() { contains_impl<QStringRef, QStringView>(); }
+ void contains_QStringRef_QChar_data() { contains_data(false); }
+ void contains_QStringRef_QChar() { contains_impl<QStringRef, QChar>(); }
+ void contains_QStringRef_char16_t_data() { contains_data(false); }
+ void contains_QStringRef_char16_t() { contains_impl<QStringRef, char16_t>(); }
void contains_QStringView_QString_data() { contains_data(); }
void contains_QStringView_QString() { contains_impl<QStringView, QString>(); }
@@ -645,12 +743,17 @@ private Q_SLOTS:
void contains_QStringView_QStringRef() { contains_impl<QStringView, QStringRef>(); }
void contains_QStringView_QStringView_data() { contains_data(); }
void contains_QStringView_QStringView() { contains_impl<QStringView, QStringView>(); }
+ void contains_QStringView_QChar_data() { contains_data(false); }
+ void contains_QStringView_QChar() { contains_impl<QStringView, QChar>(); }
+ void contains_QStringView_char16_t_data() { contains_data(false); }
+ void contains_QStringView_char16_t() { contains_impl<QStringView, char16_t>(); }
private:
template <typename Haystack, typename Needle> void lastIndexOf_impl() const;
- void lastIndexOf_data();
+ void lastIndexOf_data(bool rhsHasVariableLength = true);
private Q_SLOTS:
+ // test all combinations of {QString, QLatin1String, QStringRef, QStringView} x {QString, QLatin1String, QStringRef, QStringView, QChar, char16_t}:
void lastIndexOf_QString_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QString_QString() { lastIndexOf_impl<QString, QString>(); }
void lastIndexOf_QString_QLatin1String_data() { lastIndexOf_data(); }
@@ -659,6 +762,10 @@ private Q_SLOTS:
void lastIndexOf_QString_QStringRef() { lastIndexOf_impl<QString, QStringRef>(); }
void lastIndexOf_QString_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QString_QStringView() { lastIndexOf_impl<QString, QStringView>(); }
+ void lastIndexOf_QString_QChar_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QString_QChar() { lastIndexOf_impl<QString, QChar>(); }
+ void lastIndexOf_QString_char16_t_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QString_char16_t() { lastIndexOf_impl<QString, char16_t>(); }
void lastIndexOf_QLatin1String_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QLatin1String_QString() { lastIndexOf_impl<QLatin1String, QString>(); }
@@ -668,6 +775,10 @@ private Q_SLOTS:
void lastIndexOf_QLatin1String_QStringRef() { lastIndexOf_impl<QLatin1String, QStringRef>(); }
void lastIndexOf_QLatin1String_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QLatin1String_QStringView() { lastIndexOf_impl<QLatin1String, QStringView>(); }
+ void lastIndexOf_QLatin1String_QChar_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QLatin1String_QChar() { lastIndexOf_impl<QLatin1String, QChar>(); }
+ void lastIndexOf_QLatin1String_char16_t_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QLatin1String_char16_t() { lastIndexOf_impl<QLatin1String, char16_t>(); }
void lastIndexOf_QStringRef_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QStringRef_QString() { lastIndexOf_impl<QStringRef, QString>(); }
@@ -677,6 +788,10 @@ private Q_SLOTS:
void lastIndexOf_QStringRef_QStringRef() { lastIndexOf_impl<QStringRef, QStringRef>(); }
void lastIndexOf_QStringRef_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QStringRef_QStringView() { lastIndexOf_impl<QStringRef, QStringView>(); }
+ void lastIndexOf_QStringRef_QChar_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QStringRef_QChar() { lastIndexOf_impl<QStringRef, QChar>(); }
+ void lastIndexOf_QStringRef_char16_t_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QStringRef_char16_t() { lastIndexOf_impl<QStringRef, char16_t>(); }
void lastIndexOf_QStringView_QString_data() { lastIndexOf_data(); }
void lastIndexOf_QStringView_QString() { lastIndexOf_impl<QStringView, QString>(); }
@@ -686,6 +801,10 @@ private Q_SLOTS:
void lastIndexOf_QStringView_QStringRef() { lastIndexOf_impl<QStringView, QStringRef>(); }
void lastIndexOf_QStringView_QStringView_data() { lastIndexOf_data(); }
void lastIndexOf_QStringView_QStringView() { lastIndexOf_impl<QStringView, QStringView>(); }
+ void lastIndexOf_QStringView_QChar_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QStringView_QChar() { lastIndexOf_impl<QStringView, QChar>(); }
+ void lastIndexOf_QStringView_char16_t_data() { lastIndexOf_data(false); }
+ void lastIndexOf_QStringView_char16_t() { lastIndexOf_impl<QStringView, char16_t>(); }
};
void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty)
@@ -725,6 +844,8 @@ void tst_QStringApiSymmetry::compare_data(bool hasConceptOfNullAndEmpty)
ROW("0", "");
ROW("0", "1");
ROW("0", "0");
+ ROW("10", "0");
+ ROW("01", "1");
ROW("\xE4", "\xE4"); // ä <> ä
ROW("\xE4", "\xC4"); // ä <> Ä
#undef ROW
@@ -741,6 +862,7 @@ template <typename String> String detached(String s)
template <class Str> Str make(const QStringRef &sf, QLatin1String l1, const QByteArray &u8);
template <> QChar make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf.isEmpty() ? QChar() : sf.at(0); }
+template <> char16_t make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf.isEmpty() ? char16_t() : char16_t{sf.at(0).unicode()}; }
template <> QStringRef make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf; }
template <> QString make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf.toString(); }
template <> QStringView make(const QStringRef &sf, QLatin1String, const QByteArray &) { return sf; }
@@ -783,15 +905,6 @@ void tst_QStringApiSymmetry::compare_impl() const
const auto lhs = make<LHS>(lhsUnicode, lhsLatin1, lhsU8);
const auto rhs = make<RHS>(rhsUnicode, rhsLatin1, rhsU8);
-#ifdef Q_COMPILER_NOEXCEPT
-# define QVERIFY_NOEXCEPT(expr) do { \
- if (has_nothrow_compare<LHS, RHS>::value) {} else \
- QEXPECT_FAIL("", "Qt is missing a nothrow utf8-utf16 comparator", Continue); \
- QVERIFY(noexcept(expr)); } while (0)
-#else
-# define QVERIFY_NOEXCEPT(expr)
-#endif
-
#define CHECK(op) \
QVERIFY_NOEXCEPT(lhs op rhs); \
do { if (caseSensitiveCompareResult op 0) { \
@@ -825,15 +938,6 @@ void tst_QStringApiSymmetry::member_compare_impl() const
const auto lhs = make<LHS>(lhsUnicode, lhsLatin1, lhsU8);
const auto rhs = make<RHS>(rhsUnicode, rhsLatin1, rhsU8);
-#define QVERIFY_NOEXCEPT(expr) do { \
- if (has_nothrow_compare<LHS, RHS>::value) {} else \
- QEXPECT_FAIL("", "Qt is missing a nothrow utf8-utf16 comparator", Continue); \
- QVERIFY(noexcept(expr)); } while (0)
-
- if (std::is_same<LHS, QByteArray>::value || // needs to simply be marked as noexcept
- ((std::is_same<LHS, QString>::value || std::is_same<LHS, QStringRef>::value)
- && std::is_same<RHS, QChar>::value)) // implict QChar -> QString conversion kills noexcept
- QEXPECT_FAIL("", "known issues, will be fixed before 5.14 release", Continue);
QVERIFY_NOEXCEPT(lhs.compare(rhs, Qt::CaseSensitive));
QCOMPARE(sign(lhs.compare(rhs)), caseSensitiveCompareResult);
@@ -1646,7 +1750,7 @@ void tst_QStringApiSymmetry::toUcs4_impl()
QCOMPARE(unicode.isEmpty(), ucs4.isEmpty());
}
-void tst_QStringApiSymmetry::indexOf_data()
+void tst_QStringApiSymmetry::indexOf_data(bool rhsHasVariableLength)
{
QTest::addColumn<QString>("haystackU16");
QTest::addColumn<QLatin1String>("haystackL1");
@@ -1659,18 +1763,20 @@ void tst_QStringApiSymmetry::indexOf_data()
constexpr qsizetype zeroPos = 0;
constexpr qsizetype minus1Pos = -1;
- QTest::addRow("haystack: null, needle: null") << null << QLatin1String()
+ if (rhsHasVariableLength) {
+ QTest::addRow("haystack: null, needle: null") << null << QLatin1String()
<< null << QLatin1String() << zeroPos << zeroPos << zeroPos;
- QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("")
+ QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("")
<< null << QLatin1String() << zeroPos << zeroPos << zeroPos;
- QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << zeroPos << zeroPos << zeroPos;
- QTest::addRow("haystack: null, needle: empty") << null << QLatin1String()
+ QTest::addRow("haystack: null, needle: empty") << null << QLatin1String()
<< empty << QLatin1String("") << zeroPos << zeroPos << zeroPos;
- QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << zeroPos << zeroPos << zeroPos;
- QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("")
+ QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("")
<< empty << QLatin1String("") << zeroPos << zeroPos << zeroPos;
+ }
QTest::addRow("haystack: empty, needle: a") << empty << QLatin1String("")
<< a << QLatin1String("a") << zeroPos << minus1Pos << minus1Pos;
QTest::addRow("haystack: null, needle: a") << null << QLatin1String()
@@ -1702,17 +1808,19 @@ void tst_QStringApiSymmetry::indexOf_data()
ROW(ABC, b, 1, -1, 1);
ROW(ABC, B, 2, -1, -1);
- ROW(aBc, bc, 0, -1, 1);
- ROW(aBc, Bc, 0, 1, 1);
- ROW(aBc, bC, 0, -1, 1);
- ROW(aBc, BC, 0, -1, 1);
-
- ROW(AbC, bc, 0, -1, 1);
- ROW(AbC, Bc, 0, -1, 1);
- ROW(AbC, bC, 0, 1, 1);
- ROW(AbC, BC, 0, -1, 1);
- ROW(AbC, BC, 1, -1, 1);
- ROW(AbC, BC, 2, -1, -1);
+ if (rhsHasVariableLength) {
+ ROW(aBc, bc, 0, -1, 1);
+ ROW(aBc, Bc, 0, 1, 1);
+ ROW(aBc, bC, 0, -1, 1);
+ ROW(aBc, BC, 0, -1, 1);
+
+ ROW(AbC, bc, 0, -1, 1);
+ ROW(AbC, Bc, 0, -1, 1);
+ ROW(AbC, bC, 0, 1, 1);
+ ROW(AbC, BC, 0, -1, 1);
+ ROW(AbC, BC, 1, -1, 1);
+ ROW(AbC, BC, 2, -1, -1);
+ }
#undef ROW
}
@@ -1739,13 +1847,6 @@ void tst_QStringApiSymmetry::indexOf_impl() const
QCOMPARE(haystack.indexOf(needle, startpos), size_type(resultCS));
QCOMPARE(haystack.indexOf(needle, startpos, Qt::CaseSensitive), size_type(resultCS));
QCOMPARE(haystack.indexOf(needle, startpos, Qt::CaseInsensitive), size_type(resultCIS));
-
- if (needle.size() == 1)
- {
- QCOMPARE(haystack.indexOf(needle[0], startpos), size_type(resultCS));
- QCOMPARE(haystack.indexOf(needle[0], startpos, Qt::CaseSensitive), size_type(resultCS));
- QCOMPARE(haystack.indexOf(needle[0], startpos, Qt::CaseInsensitive), size_type(resultCIS));
- }
}
static QString ABCDEFGHIEfGEFG = QStringLiteral("ABCDEFGHIEfGEFG");
@@ -1755,7 +1856,7 @@ static QString asd = QStringLiteral("asd");
static QString asdf = QStringLiteral("asdf");
static QString Z = QStringLiteral("Z");
-void tst_QStringApiSymmetry::contains_data()
+void tst_QStringApiSymmetry::contains_data(bool rhsHasVariableLength)
{
QTest::addColumn<QString>("haystackU16");
QTest::addColumn<QLatin1String>("haystackL1");
@@ -1764,18 +1865,20 @@ void tst_QStringApiSymmetry::contains_data()
QTest::addColumn<bool>("resultCS");
QTest::addColumn<bool>("resultCIS");
- QTest::addRow("haystack: null, needle: null") << null << QLatin1String()
+ if (rhsHasVariableLength) {
+ QTest::addRow("haystack: null, needle: null") << null << QLatin1String()
<< null << QLatin1String() << true << true;
- QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("")
+ QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("")
<< null << QLatin1String() << true << true;
- QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << true << true;
- QTest::addRow("haystack: null, needle: empty") << null << QLatin1String()
+ QTest::addRow("haystack: null, needle: empty") << null << QLatin1String()
<< empty << QLatin1String("") << true << true;
- QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << true << true;;
- QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("")
+ QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("")
<< empty << QLatin1String("") << true << true;
+ }
QTest::addRow("haystack: empty, needle: a") << empty << QLatin1String("")
<< a << QLatin1String("a") << false << false;
QTest::addRow("haystack: null, needle: a") << null << QLatin1String()
@@ -1789,8 +1892,10 @@ void tst_QStringApiSymmetry::contains_data()
ROW(ABCDEFGHIEfGEFG, A, true, true);
ROW(ABCDEFGHIEfGEFG, a, false, true);
ROW(ABCDEFGHIEfGEFG, Z, false, false);
- ROW(ABCDEFGHIEfGEFG, EFG, true, true);
- ROW(ABCDEFGHIEfGEFG, efg, false, true);
+ if (rhsHasVariableLength) {
+ ROW(ABCDEFGHIEfGEFG, EFG, true, true);
+ ROW(ABCDEFGHIEfGEFG, efg, false, true);
+ }
ROW(ABCDEFGHIEfGEFG, E, true, true);
ROW(ABCDEFGHIEfGEFG, e, false, true);
#undef ROW
@@ -1815,16 +1920,9 @@ void tst_QStringApiSymmetry::contains_impl() const
QCOMPARE(haystack.contains(needle), resultCS);
QCOMPARE(haystack.contains(needle, Qt::CaseSensitive), resultCS);
QCOMPARE(haystack.contains(needle, Qt::CaseInsensitive), resultCIS);
-
- if (needle.size() == 1)
- {
- QCOMPARE(haystack.contains(needle[0]), resultCS);
- QCOMPARE(haystack.contains(needle[0], Qt::CaseSensitive), resultCS);
- QCOMPARE(haystack.contains(needle[0], Qt::CaseInsensitive), resultCIS);
- }
}
-void tst_QStringApiSymmetry::lastIndexOf_data()
+void tst_QStringApiSymmetry::lastIndexOf_data(bool rhsHasVariableLength)
{
QTest::addColumn<QString>("haystackU16");
QTest::addColumn<QLatin1String>("haystackL1");
@@ -1837,38 +1935,43 @@ void tst_QStringApiSymmetry::lastIndexOf_data()
constexpr qsizetype zeroPos = 0;
constexpr qsizetype minus1Pos = -1;
- QTest::addRow("haystack: null, needle: null") << null << QLatin1String()
+ if (rhsHasVariableLength) {
+ QTest::addRow("haystack: null, needle: null") << null << QLatin1String()
<< null << QLatin1String() << minus1Pos << minus1Pos << minus1Pos;
- QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("")
+ QTest::addRow("haystack: empty, needle: null") << empty << QLatin1String("")
<< null << QLatin1String() << minus1Pos << minus1Pos << minus1Pos;
- QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << minus1Pos << zeroPos << zeroPos;
- QTest::addRow("haystack: null, needle: empty") << null << QLatin1String()
+ QTest::addRow("haystack: null, needle: empty") << null << QLatin1String()
<< empty << QLatin1String("") << minus1Pos << minus1Pos << minus1Pos;
- QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << minus1Pos << zeroPos << zeroPos;
- QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("")
+ QTest::addRow("haystack: empty, needle: empty") << empty << QLatin1String("")
<< empty << QLatin1String("") << minus1Pos << minus1Pos << minus1Pos;
+ }
QTest::addRow("haystack: empty, needle: a") << empty << QLatin1String("")
<< a << QLatin1String("a") << minus1Pos << minus1Pos << minus1Pos;
QTest::addRow("haystack: null, needle: a") << null << QLatin1String()
<< a << QLatin1String("a") << minus1Pos << minus1Pos << minus1Pos;
- QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
+ if (rhsHasVariableLength) {
+ QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << qsizetype(1) << qsizetype(1) << qsizetype(1);
- QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << qsizetype(1) << qsizetype(1) << qsizetype(1);
- QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: null") << a << QLatin1String("a")
<< null << QLatin1String() << qsizetype(2) << minus1Pos << minus1Pos;
- QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
+ QTest::addRow("haystack: a, needle: empty") << a << QLatin1String("a")
<< empty << QLatin1String("") << qsizetype(2) << minus1Pos << minus1Pos;
+ }
#define ROW(h, n, st, cs, cis) \
QTest::addRow("haystack: %s, needle: %s", #h, #n) << h << QLatin1String(#h) \
<< n << QLatin1String(#n) \
<< qsizetype(st) << qsizetype(cs) << qsizetype(cis)
- ROW(asd, asdf, -1, -1, -1);
+ if (rhsHasVariableLength)
+ ROW(asd, asdf, -1, -1, -1);
ROW(ABCDEFGHIEfGEFG, G, -1, 14, 14);
ROW(ABCDEFGHIEfGEFG, g, -1, -1, 14);
@@ -1895,13 +1998,15 @@ void tst_QStringApiSymmetry::lastIndexOf_data()
ROW(ABCDEFGHIEfGEFG, A, -15, 0, 0);
ROW(ABCDEFGHIEfGEFG, a, -15, -1, 0);
- ROW(ABCDEFGHIEfGEFG, efg, 0, -1, -1);
- ROW(ABCDEFGHIEfGEFG, efg, 15, -1, -1);
- ROW(ABCDEFGHIEfGEFG, efg, -15, -1, -1);
- ROW(ABCDEFGHIEfGEFG, efg, 14, -1, 12);
- ROW(ABCDEFGHIEfGEFG, efg, 12, -1, 12);
- ROW(ABCDEFGHIEfGEFG, efg, -12, -1, -1);
- ROW(ABCDEFGHIEfGEFG, efg, 11, -1, 9);
+ if (rhsHasVariableLength) {
+ ROW(ABCDEFGHIEfGEFG, efg, 0, -1, -1);
+ ROW(ABCDEFGHIEfGEFG, efg, 15, -1, -1);
+ ROW(ABCDEFGHIEfGEFG, efg, -15, -1, -1);
+ ROW(ABCDEFGHIEfGEFG, efg, 14, -1, 12);
+ ROW(ABCDEFGHIEfGEFG, efg, 12, -1, 12);
+ ROW(ABCDEFGHIEfGEFG, efg, -12, -1, -1);
+ ROW(ABCDEFGHIEfGEFG, efg, 11, -1, 9);
+ }
#undef ROW
}
@@ -1928,12 +2033,6 @@ void tst_QStringApiSymmetry::lastIndexOf_impl() const
QCOMPARE(haystack.lastIndexOf(needle, startpos, Qt::CaseSensitive), size_type(resultCS));
QCOMPARE(haystack.lastIndexOf(needle, startpos, Qt::CaseInsensitive), size_type(resultCIS));
- if (needle.size() == 1)
- {
- QCOMPARE(haystack.lastIndexOf(needle[0], startpos), size_type(resultCS));
- QCOMPARE(haystack.lastIndexOf(needle[0], startpos, Qt::CaseSensitive), size_type(resultCS));
- QCOMPARE(haystack.lastIndexOf(needle[0], startpos, Qt::CaseInsensitive), size_type(resultCIS));
- }
}
QTEST_APPLESS_MAIN(tst_QStringApiSymmetry)
diff --git a/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp
new file mode 100644
index 0000000000..b681676d09
--- /dev/null
+++ b/tests/auto/corelib/tools/qlinkedlist/tst_qlinkedlist.cpp
@@ -0,0 +1,1148 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QLinkedList>
+
+#if QT_DEPRECATED_SINCE(5, 15)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
+struct Movable
+{
+ Movable(char input = 'j') : i(input), state(Constructed)
+ {
+ ++liveCount;
+ }
+ Movable(const Movable &other)
+ : i(other.i)
+ , state(Constructed)
+ {
+ check(other.state, Constructed);
+ ++liveCount;
+ }
+
+ ~Movable()
+ {
+ check(state, Constructed);
+ i = 0;
+ --liveCount;
+ state = Destructed;
+ }
+
+ bool operator ==(const Movable &other) const
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ return i == other.i;
+ }
+
+ Movable &operator=(const Movable &other)
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ return *this;
+ }
+ char i;
+
+ static int getLiveCount() { return liveCount; }
+private:
+ static int liveCount;
+
+ enum State { Constructed = 106, Destructed = 110 };
+ State state;
+
+ static void check(const State state1, const State state2)
+ {
+ QCOMPARE(int(state1), int(state2));
+ }
+};
+
+int Movable::liveCount = 0;
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(Movable, Q_MOVABLE_TYPE);
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Movable);
+
+Q_DECLARE_METATYPE(QLinkedList<int>);
+
+
+int qHash(const Movable& movable)
+{
+ return qHash(movable.i);
+}
+
+struct Complex
+{
+ Complex(int val = 0)
+ : value(val)
+ , checkSum(this)
+ {
+ ++liveCount;
+ }
+
+ Complex(Complex const &other)
+ : value(other.value)
+ , checkSum(this)
+ {
+ ++liveCount;
+ }
+
+ Complex &operator=(Complex const &other)
+ {
+ check(); other.check();
+
+ value = other.value;
+ return *this;
+ }
+
+ ~Complex()
+ {
+ --liveCount;
+ check();
+ }
+
+ operator int() const { return value; }
+
+ bool operator==(Complex const &other) const
+ {
+ check(); other.check();
+ return value == other.value;
+ }
+
+ void check() const
+ {
+ QVERIFY(this == checkSum);
+ }
+
+ static int getLiveCount() { return liveCount; }
+private:
+ static int liveCount;
+
+ int value;
+ void *checkSum;
+};
+
+int Complex::liveCount = 0;
+
+Q_DECLARE_METATYPE(Complex);
+
+// Tests depend on the fact that:
+Q_STATIC_ASSERT(!QTypeInfo<int>::isStatic);
+Q_STATIC_ASSERT(!QTypeInfo<int>::isComplex);
+Q_STATIC_ASSERT(!QTypeInfo<Movable>::isStatic);
+Q_STATIC_ASSERT(QTypeInfo<Movable>::isComplex);
+Q_STATIC_ASSERT(QTypeInfo<Complex>::isStatic);
+Q_STATIC_ASSERT(QTypeInfo<Complex>::isComplex);
+
+class tst_QLinkedList : public QObject
+{
+ Q_OBJECT
+private slots:
+ void eraseValidIteratorsOnSharedList() const;
+ void insertWithIteratorsOnSharedList() const;
+ void lengthInt() const;
+ void lengthMovable() const;
+ void lengthComplex() const;
+ void lengthSignature() const;
+ void firstInt() const;
+ void firstMovable() const;
+ void firstComplex() const;
+ void lastInt() const;
+ void lastMovable() const;
+ void lastComplex() const;
+ void beginInt() const;
+ void beginMovable() const;
+ void beginComplex() const;
+ void endInt() const;
+ void endMovable() const;
+ void endComplex() const;
+ void containsInt() const;
+ void containsMovable() const;
+ void containsComplex() const;
+ void countInt() const;
+ void countMovable() const;
+ void countComplex() const;
+ void cpp17ctad() const;
+ void emptyInt() const;
+ void emptyMovable() const;
+ void emptyComplex() const;
+ void endsWithInt() const;
+ void endsWithMovable() const;
+ void endsWithComplex() const;
+ void removeAllInt() const;
+ void removeAllMovable() const;
+ void removeAllComplex() const;
+ void removeOneInt() const;
+ void removeOneMovable() const;
+ void removeOneComplex() const;
+ void reverseIterators() const;
+ void startsWithInt() const;
+ void startsWithMovable() const;
+ void startsWithComplex() const;
+ void takeFirstInt() const;
+ void takeFirstMovable() const;
+ void takeFirstComplex() const;
+ void takeLastInt() const;
+ void takeLastMovable() const;
+ void takeLastComplex() const;
+ void toStdListInt() const;
+ void toStdListMovable() const;
+ void toStdListComplex() const;
+ void testOperatorsInt() const;
+ void testOperatorsMovable() const;
+ void testOperatorsComplex() const;
+ void testSTLIteratorsInt() const;
+ void testSTLIteratorsMovable() const;
+ void testSTLIteratorsComplex() const;
+
+ void initializeList() const;
+
+ void constSharedNullInt() const;
+ void constSharedNullMovable() const;
+ void constSharedNullComplex() const;
+
+ void setSharableInt() const;
+private:
+ template<typename T> void length() const;
+ template<typename T> void first() const;
+ template<typename T> void last() const;
+ template<typename T> void begin() const;
+ template<typename T> void end() const;
+ template<typename T> void contains() const;
+ template<typename T> void count() const;
+ template<typename T> void empty() const;
+ template<typename T> void endsWith() const;
+ template<typename T> void move() const;
+ template<typename T> void removeAll() const;
+ template<typename T> void removeOne() const;
+ template<typename T> void startsWith() const;
+ template<typename T> void swap() const;
+ template<typename T> void takeFirst() const;
+ template<typename T> void takeLast() const;
+ template<typename T> void toStdList() const;
+ template<typename T> void value() const;
+
+ template<typename T> void testOperators() const;
+ template<typename T> void testSTLIterators() const;
+
+ template<typename T> void constSharedNull() const;
+
+ int dummyForGuard;
+};
+
+template<typename T> struct SimpleValue
+{
+ static T at(int index)
+ {
+ return values[index % maxSize];
+ }
+ static const uint maxSize = 7;
+ static const T values[maxSize];
+};
+
+template<>
+const int SimpleValue<int>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
+template<>
+const Movable SimpleValue<Movable>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
+template<>
+const Complex SimpleValue<Complex>::values[] = { 10, 20, 30, 40, 100, 101, 102 };
+
+// Make some macros for the tests to use in order to be slightly more readable...
+#define T_FOO SimpleValue<T>::at(0)
+#define T_BAR SimpleValue<T>::at(1)
+#define T_BAZ SimpleValue<T>::at(2)
+#define T_CAT SimpleValue<T>::at(3)
+#define T_DOG SimpleValue<T>::at(4)
+#define T_BLAH SimpleValue<T>::at(5)
+#define T_WEEE SimpleValue<T>::at(6)
+
+template<typename T>
+void tst_QLinkedList::length() const
+{
+ /* Empty list. */
+ {
+ const QLinkedList<T> list;
+ QCOMPARE(list.size(), 0);
+ }
+
+ /* One entry. */
+ {
+ QLinkedList<T> list;
+ list.append(T_FOO);
+ QCOMPARE(list.size(), 1);
+ }
+
+ /* Two entries. */
+ {
+ QLinkedList<T> list;
+ list.append(T_FOO);
+ list.append(T_BAR);
+ QCOMPARE(list.size(), 2);
+ }
+
+ /* Three entries. */
+ {
+ QLinkedList<T> list;
+ list.append(T_FOO);
+ list.append(T_BAR);
+ list.append(T_BAZ);
+ QCOMPARE(list.size(), 3);
+ }
+}
+
+void tst_QLinkedList::eraseValidIteratorsOnSharedList() const
+{
+ QLinkedList<int> a, b;
+ a.append(5);
+ a.append(10);
+ a.append(20);
+ a.append(20);
+ a.append(20);
+ a.append(20);
+ a.append(30);
+
+ QLinkedList<int>::iterator i = a.begin();
+ ++i;
+ ++i;
+ ++i;
+ b = a;
+ QLinkedList<int>::iterator r = a.erase(i);
+ QCOMPARE(b.size(), 7);
+ QCOMPARE(a.size(), 6);
+ --r;
+ --r;
+ QCOMPARE(*r, 10); // Ensure that number 2 instance was removed;
+}
+
+void tst_QLinkedList::insertWithIteratorsOnSharedList() const
+{
+ QLinkedList<int> a, b;
+ a.append(5);
+ a.append(10);
+ a.append(20);
+ QLinkedList<int>::iterator i = a.begin();
+ ++i;
+ ++i;
+ b = a;
+
+ QLinkedList<int>::iterator i2 = a.insert(i, 15);
+ QCOMPARE(b.size(), 3);
+ QCOMPARE(a.size(), 4);
+ --i2;
+ QCOMPARE(*i2, 10);
+}
+
+void tst_QLinkedList::lengthInt() const
+{
+ length<int>();
+}
+
+void tst_QLinkedList::lengthMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ length<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::lengthComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ length<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+void tst_QLinkedList::lengthSignature() const
+{
+ /* Constness. */
+ {
+ const QLinkedList<int> list;
+ /* The function should be const. */
+ list.size();
+ }
+}
+
+template<typename T>
+void tst_QLinkedList::first() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(list.first(), T_FOO);
+
+ // remove an item, make sure it still works
+ list.pop_front();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(list.first(), T_BAR);
+}
+
+void tst_QLinkedList::firstInt() const
+{
+ first<int>();
+}
+
+void tst_QLinkedList::firstMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ first<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::firstComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ first<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::last() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(list.last(), T_BAR);
+
+ // remove an item, make sure it still works
+ list.pop_back();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(list.last(), T_FOO);
+}
+
+void tst_QLinkedList::lastInt() const
+{
+ last<int>();
+}
+
+void tst_QLinkedList::lastMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ last<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::lastComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ last<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::begin() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(*list.begin(), T_FOO);
+
+ // remove an item, make sure it still works
+ list.pop_front();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(*list.begin(), T_BAR);
+}
+
+void tst_QLinkedList::beginInt() const
+{
+ begin<int>();
+}
+
+void tst_QLinkedList::beginMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ begin<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::beginComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ begin<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::end() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR;
+
+ QCOMPARE(*--list.end(), T_BAR);
+
+ // remove an item, make sure it still works
+ list.pop_back();
+ QVERIFY(list.size() == 1);
+ QCOMPARE(*--list.end(), T_FOO);
+}
+
+void tst_QLinkedList::endInt() const
+{
+ end<int>();
+}
+
+void tst_QLinkedList::endMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ end<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::endComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ end<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::contains() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QVERIFY(list.contains(T_FOO));
+ QVERIFY(list.contains(T_BLAH) != true);
+
+ // add it and make sure it matches
+ list.append(T_BLAH);
+ QVERIFY(list.contains(T_BLAH));
+}
+
+void tst_QLinkedList::containsInt() const
+{
+ contains<int>();
+}
+
+void tst_QLinkedList::containsMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ contains<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::containsComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ contains<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::count() const
+{
+ QLinkedList<T> list;
+
+ // starts empty
+ QVERIFY(list.count() == 0);
+
+ // goes up
+ list.append(T_FOO);
+ QVERIFY(list.count() == 1);
+
+ // and up
+ list.append(T_BAR);
+ QVERIFY(list.count() == 2);
+
+ // and down
+ list.pop_back();
+ QVERIFY(list.count() == 1);
+
+ // and empty. :)
+ list.pop_back();
+ QVERIFY(list.count() == 0);
+}
+
+void tst_QLinkedList::countInt() const
+{
+ count<int>();
+}
+
+void tst_QLinkedList::countMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ count<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::countComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ count<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+void tst_QLinkedList::cpp17ctad() const
+{
+#ifdef __cpp_deduction_guides
+#define QVERIFY_IS_LIST_OF(obj, Type) \
+ QVERIFY2((std::is_same<decltype(obj), QLinkedList<Type>>::value), \
+ QMetaType::typeName(qMetaTypeId<decltype(obj)::value_type>()))
+#define CHECK(Type, One, Two, Three) \
+ do { \
+ const Type v[] = {One, Two, Three}; \
+ QLinkedList v1 = {One, Two, Three}; \
+ QVERIFY_IS_LIST_OF(v1, Type); \
+ QLinkedList v2(v1.begin(), v1.end()); \
+ QVERIFY_IS_LIST_OF(v2, Type); \
+ QLinkedList v3(std::begin(v), std::end(v)); \
+ QVERIFY_IS_LIST_OF(v3, Type); \
+ } while (false) \
+ /*end*/
+ CHECK(int, 1, 2, 3);
+ CHECK(double, 1.0, 2.0, 3.0);
+ CHECK(QString, QStringLiteral("one"), QStringLiteral("two"), QStringLiteral("three"));
+#undef QVERIFY_IS_LIST_OF
+#undef CHECK
+#else
+ QSKIP("This test requires C++17 Constructor Template Argument Deduction support enabled in the compiler.");
+#endif
+}
+
+template<typename T>
+void tst_QLinkedList::empty() const
+{
+ QLinkedList<T> list;
+
+ // make sure it starts empty
+ QVERIFY(list.empty());
+
+ // and doesn't stay empty
+ list.append(T_FOO);
+ QVERIFY(!list.empty());
+
+ // and goes back to being empty
+ list.pop_back();
+ QVERIFY(list.empty());
+}
+
+void tst_QLinkedList::emptyInt() const
+{
+ empty<int>();
+}
+
+void tst_QLinkedList::emptyMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ empty<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::emptyComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ empty<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::endsWith() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // test it returns correctly in both cases
+ QVERIFY(list.endsWith(T_BAZ));
+ QVERIFY(!list.endsWith(T_BAR));
+
+ // remove an item and make sure the end item changes
+ list.pop_back();
+ QVERIFY(list.endsWith(T_BAR));
+}
+
+void tst_QLinkedList::endsWithInt() const
+{
+ endsWith<int>();
+}
+
+void tst_QLinkedList::endsWithMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ endsWith<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::endsWithComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ endsWith<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::removeAll() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // remove one instance
+ list.removeAll(T_BAR);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ);
+
+ // many instances
+ list << T_FOO << T_BAR << T_BAZ << T_FOO << T_BAR << T_BAZ << T_FOO << T_BAR << T_BAZ;
+ list.removeAll(T_BAR);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ);
+
+ // try remove something that doesn't exist
+ list.removeAll(T_WEEE);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ << T_FOO << T_BAZ);
+}
+
+void tst_QLinkedList::removeAllInt() const
+{
+ removeAll<int>();
+}
+
+void tst_QLinkedList::removeAllMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ removeAll<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::removeAllComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ removeAll<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::removeOne() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // middle
+ list.removeOne(T_BAR);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAZ);
+
+ // start
+ list.removeOne(T_FOO);
+ QCOMPARE(list, QLinkedList<T>() << T_BAZ);
+
+ // last
+ list.removeOne(T_BAZ);
+ QCOMPARE(list, QLinkedList<T>());
+
+ // make sure it really only removes one :)
+ list << T_FOO << T_FOO;
+ list.removeOne(T_FOO);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO);
+
+ // try remove something that doesn't exist
+ list.removeOne(T_WEEE);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO);
+}
+
+void tst_QLinkedList::removeOneInt() const
+{
+ removeOne<int>();
+}
+
+void tst_QLinkedList::removeOneMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ removeOne<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::removeOneComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ removeOne<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+void tst_QLinkedList::reverseIterators() const
+{
+ QLinkedList<int> l;
+ l << 1 << 2 << 3 << 4;
+ QLinkedList<int> lr = l;
+ std::reverse(lr.begin(), lr.end());
+ const QLinkedList<int> &clr = lr;
+ QVERIFY(std::equal(l.begin(), l.end(), lr.rbegin()));
+ QVERIFY(std::equal(l.begin(), l.end(), lr.crbegin()));
+ QVERIFY(std::equal(l.begin(), l.end(), clr.rbegin()));
+ QVERIFY(std::equal(lr.rbegin(), lr.rend(), l.begin()));
+ QVERIFY(std::equal(lr.crbegin(), lr.crend(), l.begin()));
+ QVERIFY(std::equal(clr.rbegin(), clr.rend(), l.begin()));
+}
+
+template<typename T>
+void tst_QLinkedList::startsWith() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // make sure it starts ok
+ QVERIFY(list.startsWith(T_FOO));
+
+ // remove an item
+ list.removeFirst();
+ QVERIFY(list.startsWith(T_BAR));
+}
+
+void tst_QLinkedList::startsWithInt() const
+{
+ startsWith<int>();
+}
+
+void tst_QLinkedList::startsWithMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ startsWith<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::startsWithComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ startsWith<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::takeFirst() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QCOMPARE(list.takeFirst(), T_FOO);
+ QVERIFY(list.size() == 2);
+ QCOMPARE(list.takeFirst(), T_BAR);
+ QVERIFY(list.size() == 1);
+ QCOMPARE(list.takeFirst(), T_BAZ);
+ QVERIFY(list.size() == 0);
+}
+
+void tst_QLinkedList::takeFirstInt() const
+{
+ takeFirst<int>();
+}
+
+void tst_QLinkedList::takeFirstMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ takeFirst<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::takeFirstComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ takeFirst<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::takeLast() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QCOMPARE(list.takeLast(), T_BAZ);
+ QCOMPARE(list.takeLast(), T_BAR);
+ QCOMPARE(list.takeLast(), T_FOO);
+}
+
+void tst_QLinkedList::takeLastInt() const
+{
+ takeLast<int>();
+}
+
+void tst_QLinkedList::takeLastMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ takeLast<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::takeLastComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ takeLast<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::toStdList() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ // yuck.
+ std::list<T> slist;
+ slist.push_back(T_FOO);
+ slist.push_back(T_BAR);
+ slist.push_back(T_BAZ);
+
+ QCOMPARE(list.toStdList(), slist);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ);
+}
+
+void tst_QLinkedList::toStdListInt() const
+{
+ toStdList<int>();
+}
+
+void tst_QLinkedList::toStdListMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ toStdList<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::toStdListComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ toStdList<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::testOperators() const
+{
+ QLinkedList<T> list;
+ list << T_FOO << T_BAR << T_BAZ;
+
+ QLinkedList<T> listtwo;
+ listtwo << T_FOO << T_BAR << T_BAZ;
+
+ // test equal
+ QVERIFY(list == listtwo);
+
+ // not equal
+ listtwo.append(T_CAT);
+ QVERIFY(list != listtwo);
+
+ // +=
+ list += listtwo;
+ QVERIFY(list.size() == 7);
+ QVERIFY(listtwo.size() == 4);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ
+ << T_FOO << T_BAR << T_BAZ << T_CAT);
+
+ // =
+ list = listtwo;
+ QCOMPARE(list, listtwo);
+ QCOMPARE(list, QLinkedList<T>() << T_FOO << T_BAR << T_BAZ << T_CAT);
+}
+
+void tst_QLinkedList::testOperatorsInt() const
+{
+ testOperators<int>();
+}
+
+void tst_QLinkedList::testOperatorsMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ testOperators<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::testOperatorsComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ testOperators<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+template<typename T>
+void tst_QLinkedList::testSTLIterators() const
+{
+ QLinkedList<T> list;
+
+ // create a list
+ list << T_FOO << T_BAR << T_BAZ;
+ typename QLinkedList<T>::iterator it = list.begin();
+ QCOMPARE(*it, T_FOO); it++;
+ QCOMPARE(*it, T_BAR); it++;
+ QCOMPARE(*it, T_BAZ); it++;
+ QCOMPARE(it, list.end()); it--;
+
+ // walk backwards
+ QCOMPARE(*it, T_BAZ); it--;
+ QCOMPARE(*it, T_BAR); it--;
+ QCOMPARE(*it, T_FOO);
+
+ // test erase
+ it = list.erase(it);
+ QVERIFY(list.size() == 2);
+ QCOMPARE(*it, T_BAR);
+
+ // test multiple erase
+ it = list.erase(it, it + 2);
+ QVERIFY(list.size() == 0);
+ QCOMPARE(it, list.end());
+
+ // insert again
+ it = list.insert(it, T_FOO);
+ QVERIFY(list.size() == 1);
+ QCOMPARE(*it, T_FOO);
+
+ // insert again
+ it = list.insert(it, T_BAR);
+ QVERIFY(list.size() == 2);
+ QCOMPARE(*it++, T_BAR);
+ QCOMPARE(*it, T_FOO);
+}
+
+void tst_QLinkedList::testSTLIteratorsInt() const
+{
+ testSTLIterators<int>();
+}
+
+void tst_QLinkedList::testSTLIteratorsMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ testSTLIterators<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::testSTLIteratorsComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ testSTLIterators<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+void tst_QLinkedList::initializeList() const
+{
+ QLinkedList<int> v1 { 2, 3, 4 };
+ QCOMPARE(v1, QLinkedList<int>() << 2 << 3 << 4);
+ QCOMPARE(v1, (QLinkedList<int> { 2, 3, 4}));
+
+ QLinkedList<QLinkedList<int>> v2{ v1, { 1 }, QLinkedList<int>(), { 2, 3, 4 } };
+ QLinkedList<QLinkedList<int>> v3;
+ v3 << v1 << (QLinkedList<int>() << 1) << QLinkedList<int>() << v1;
+ QCOMPARE(v3, v2);
+}
+
+
+template<typename T>
+void tst_QLinkedList::constSharedNull() const
+{
+ QLinkedList<T> list2;
+#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
+ QLinkedList<T> list1;
+ list1.setSharable(false);
+ QVERIFY(list1.isDetached());
+
+ list2.setSharable(true);
+#endif
+ QVERIFY(!list2.isDetached());
+}
+
+void tst_QLinkedList::constSharedNullInt() const
+{
+ constSharedNull<int>();
+}
+
+void tst_QLinkedList::constSharedNullMovable() const
+{
+ const int liveCount = Movable::getLiveCount();
+ constSharedNull<Movable>();
+ QCOMPARE(liveCount, Movable::getLiveCount());
+}
+
+void tst_QLinkedList::constSharedNullComplex() const
+{
+ const int liveCount = Complex::getLiveCount();
+ constSharedNull<Complex>();
+ QCOMPARE(liveCount, Complex::getLiveCount());
+}
+
+
+void tst_QLinkedList::setSharableInt() const
+{
+#if !defined(QT_NO_UNSHARABLE_CONTAINERS)
+ QLinkedList<int> orglist;
+ orglist << 0 << 1 << 2 << 3 << 4 << 5;
+ int size = 6;
+
+ QLinkedList<int> list;
+ list = orglist;
+
+ QVERIFY(!list.isDetached());
+ list.setSharable(true);
+
+ QCOMPARE(list.size(), size);
+
+ {
+ QLinkedList<int> copy(list);
+ QVERIFY(!copy.isDetached());
+ QVERIFY(copy.isSharedWith(list));
+ }
+
+ list.setSharable(false);
+ QVERIFY(list.isDetached() || list.isSharedWith(QLinkedList<int>()));
+
+ {
+ QLinkedList<int> copy(list);
+
+ QVERIFY(copy.isDetached() || copy.isSharedWith(QLinkedList<int>()));
+ QCOMPARE(copy.size(), size);
+ QCOMPARE(copy, list);
+ }
+
+ list.setSharable(true);
+
+ {
+ QLinkedList<int> copy(list);
+
+ QVERIFY(!copy.isDetached());
+ QVERIFY(copy.isSharedWith(list));
+ }
+
+ QLinkedList<int>::const_iterator it = list.constBegin();
+ for (int i = 0; i < list.size(); ++i) {
+ QCOMPARE(int(*it), i);
+ ++it;
+ }
+
+ QCOMPARE(list.size(), size);
+#endif
+}
+
+QT_WARNING_POP
+#else
+class tst_QLinkedList : public QObject
+{
+ Q_OBJECT
+private slots:
+ void initTestCase() { QSKIP("Deprecated APIs are disabled, skipping this test."); }
+};
+
+#endif // QT_DEPRECATED_SINCE(5, 15)
+
+QTEST_APPLESS_MAIN(tst_QLinkedList)
+#include "tst_qlinkedlist.moc"
diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
index 7418f447e6..ce88c6a7a4 100644
--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
+++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
@@ -46,6 +46,7 @@
#include <private/qdrawhelper_p.h>
#include <qpainter.h>
+#include <qpainterpath.h>
#include <qqueue.h>
#include <qscreen.h>
diff --git a/tests/auto/gui/painting/qregion/tst_qregion.cpp b/tests/auto/gui/painting/qregion/tst_qregion.cpp
index d1ea7706b9..aa9a84ba8e 100644
--- a/tests/auto/gui/painting/qregion/tst_qregion.cpp
+++ b/tests/auto/gui/painting/qregion/tst_qregion.cpp
@@ -32,6 +32,7 @@
#include <qbitmap.h>
#include <qpainter.h>
+#include <qpainterpath.h>
#include <qpolygon.h>
class tst_QRegion : public QObject
diff --git a/tests/auto/gui/painting/qtransform/tst_qtransform.cpp b/tests/auto/gui/painting/qtransform/tst_qtransform.cpp
index 97c6ad60b8..2dcb564e2b 100644
--- a/tests/auto/gui/painting/qtransform/tst_qtransform.cpp
+++ b/tests/auto/gui/painting/qtransform/tst_qtransform.cpp
@@ -28,11 +28,11 @@
#include <QtTest/QtTest>
-#include "qtransform.h"
+#include <qpainterpath.h>
#include <qpolygon.h>
+#include <qtransform.h>
#include <qdebug.h>
-
class tst_QTransform : public QObject
{
Q_OBJECT
diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp
index 8dd8b95daf..ad0dfb5c08 100644
--- a/tests/auto/gui/qopengl/tst_qopengl.cpp
+++ b/tests/auto/gui/qopengl/tst_qopengl.cpp
@@ -36,6 +36,7 @@
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLFunctions_4_2_Core>
#include <QtGui/QPainter>
+#include <QtGui/QPainterPath>
#include <QtGui/QScreen>
#include <QtGui/QWindow>
#include <QtGui/QOffscreenSurface>
diff --git a/tests/auto/gui/rhi/qrhi/data/buildshaders.bat b/tests/auto/gui/rhi/qrhi/data/buildshaders.bat
index 5b8a77b833..0cfeaaaff3 100644
--- a/tests/auto/gui/rhi/qrhi/data/buildshaders.bat
+++ b/tests/auto/gui/rhi/qrhi/data/buildshaders.bat
@@ -44,5 +44,6 @@ qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.vert.qsb simple.vert
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simple.frag.qsb simple.frag
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.vert.qsb simpletextured.vert
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o simpletextured.frag.qsb simpletextured.frag
+qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 20 -o simpletextured_array.frag.qsb simpletextured_array.frag
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.vert.qsb textured.vert
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured.frag.qsb textured.frag
diff --git a/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb
index c235108d39..43edbdffd9 100644
--- a/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb
+++ b/tests/auto/gui/rhi/qrhi/data/simple.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb b/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb
index 68cfeb8f1d..06af5df492 100644
--- a/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb
+++ b/tests/auto/gui/rhi/qrhi/data/simple.vert.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb
index 397961c238..7749f3caad 100644
--- a/tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb
+++ b/tests/auto/gui/rhi/qrhi/data/simpletextured.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb
index a9067949a5..c87d4b2fc1 100644
--- a/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb
+++ b/tests/auto/gui/rhi/qrhi/data/simpletextured.vert.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag b/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag
new file mode 100644
index 0000000000..c5ee2057d8
--- /dev/null
+++ b/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag
@@ -0,0 +1,17 @@
+#version 440
+
+layout(location = 0) in vec2 uv;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 0) uniform sampler2D tex[3];
+
+void main()
+{
+ vec4 c0 = texture(tex[0], uv);
+ vec4 c1 = texture(tex[1], uv);
+ vec4 c2 = texture(tex[2], uv);
+ vec4 cc = c0 + c1 + c2;
+ vec4 c = vec4(clamp(cc.r, 0.0, 1.0), clamp(cc.g, 0.0, 1.0), clamp(cc.b, 0.0, 1.0), clamp(cc.a, 0.0, 1.0));
+ c.rgb *= c.a;
+ fragColor = c;
+}
diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag.qsb
new file mode 100644
index 0000000000..362e220d25
--- /dev/null
+++ b/tests/auto/gui/rhi/qrhi/data/simpletextured_array.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/data/textured.frag.qsb b/tests/auto/gui/rhi/qrhi/data/textured.frag.qsb
index 018d732e2f..f669152c9c 100644
--- a/tests/auto/gui/rhi/qrhi/data/textured.frag.qsb
+++ b/tests/auto/gui/rhi/qrhi/data/textured.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb b/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb
index 44454d226e..d4ba474777 100644
--- a/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb
+++ b/tests/auto/gui/rhi/qrhi/data/textured.vert.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
index 549481aa21..c1793d7d4a 100644
--- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
+++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
@@ -91,6 +91,8 @@ private slots:
void renderToTextureSimple();
void renderToTextureTexturedQuad_data();
void renderToTextureTexturedQuad();
+ void renderToTextureArrayOfTexturedQuad_data();
+ void renderToTextureArrayOfTexturedQuad();
void renderToTextureTexturedQuadAndUniformBuffer_data();
void renderToTextureTexturedQuadAndUniformBuffer();
void renderToWindowSimple_data();
@@ -1468,6 +1470,147 @@ void tst_QRhi::renderToTextureTexturedQuad()
QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qBlue(result.pixel(214, 191)));
}
+void tst_QRhi::renderToTextureArrayOfTexturedQuad_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::renderToTextureArrayOfTexturedQuad()
+{
+ QFETCH(QRhi::Implementation, impl);
+ QFETCH(QRhiInitParams *, initParams);
+
+ QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
+ if (!rhi)
+ QSKIP("QRhi could not be created, skipping testing rendering");
+
+ QImage inputImage;
+ inputImage.load(QLatin1String(":/data/qt256.png"));
+ QVERIFY(!inputImage.isNull());
+
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size(), 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(texture->build());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->build());
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+
+ QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
+
+ static const float verticesUvs[] = {
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, -1.0f, 1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f
+ };
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(verticesUvs)));
+ QVERIFY(vbuf->build());
+ updates->uploadStaticBuffer(vbuf.data(), verticesUvs);
+
+ // In this test we pass 3 textures (and samplers) to the fragment shader in
+ // form of an array of combined image samplers.
+
+ QScopedPointer<QRhiTexture> inputTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size()));
+ QVERIFY(inputTexture->build());
+ updates->uploadTexture(inputTexture.data(), inputImage);
+
+ QImage redImage(inputImage.size(), QImage::Format_RGBA8888);
+ redImage.fill(Qt::red);
+
+ QScopedPointer<QRhiTexture> redTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size()));
+ QVERIFY(redTexture->build());
+ updates->uploadTexture(redTexture.data(), redImage);
+
+ QImage greenImage(inputImage.size(), QImage::Format_RGBA8888);
+ greenImage.fill(Qt::green);
+
+ QScopedPointer<QRhiTexture> greenTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size()));
+ QVERIFY(greenTexture->build());
+ updates->uploadTexture(greenTexture.data(), greenImage);
+
+ QScopedPointer<QRhiSampler> sampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ QVERIFY(sampler->build());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
+ QRhiShaderResourceBinding::TextureAndSampler texSamplers[3] = {
+ { inputTexture.data(), sampler.data() },
+ { redTexture.data(), sampler.data() },
+ { greenTexture.data(), sampler.data() }
+ };
+ srb->setBindings({
+ QRhiShaderResourceBinding::sampledTextures(0, QRhiShaderResourceBinding::FragmentStage, 3, texSamplers)
+ });
+ QVERIFY(srb->build());
+
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
+ pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
+ QShader vs = loadShader(":/data/simpletextured.vert.qsb");
+ QVERIFY(vs.isValid());
+ QShader fs = loadShader(":/data/simpletextured_array.frag.qsb");
+ QVERIFY(fs.isValid());
+ pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({ { 4 * sizeof(float) } });
+ inputLayout.setAttributes({
+ { 0, 0, QRhiVertexInputAttribute::Float2, 0 },
+ { 0, 1, QRhiVertexInputAttribute::Float2, 2 * sizeof(float) }
+ });
+ pipeline->setVertexInputLayout(inputLayout);
+ pipeline->setShaderResourceBindings(srb.data());
+ pipeline->setRenderPassDescriptor(rpDesc.data());
+
+ QVERIFY(pipeline->build());
+
+ cb->beginPass(rt.data(), Qt::black, { 1.0f, 0 }, updates);
+ cb->setGraphicsPipeline(pipeline.data());
+ cb->setShaderResources();
+ cb->setViewport({ 0, 0, float(texture->pixelSize().width()), float(texture->pixelSize().height()) });
+ QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
+ cb->setVertexInput(0, 1, &vbindings);
+ cb->draw(4);
+
+ QRhiReadbackResult readResult;
+ QImage result;
+ readResult.completed = [&readResult, &result] {
+ result = QImage(reinterpret_cast<const uchar *>(readResult.data.constData()),
+ readResult.pixelSize.width(), readResult.pixelSize.height(),
+ QImage::Format_RGBA8888_Premultiplied);
+ };
+ QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
+ readbackBatch->readBackTexture({ texture.data() }, &readResult);
+ cb->endPass(readbackBatch);
+
+ rhi->endOffscreenFrame();
+
+ QVERIFY(!result.isNull());
+
+ if (impl == QRhi::Null)
+ return;
+
+ // Flip with D3D and Metal because these have Y down in images. Vulkan does
+ // not need this because there Y is down both in images and in NDC, which
+ // just happens to give correct results with our OpenGL-targeted vertex and
+ // UV data.
+ if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC())
+ result = std::move(result).mirrored();
+
+ // we added the input image + red + green together, so red and green must be all 1
+ for (int y = 0; y < result.height(); ++y) {
+ for (int x = 0; x < result.width(); ++x) {
+ const QRgb pixel = result.pixel(x, y);
+ QCOMPARE(qRed(pixel), 255);
+ QCOMPARE(qGreen(pixel), 255);
+ }
+ }
+}
+
void tst_QRhi::renderToTextureTexturedQuadAndUniformBuffer_data()
{
rhiTestData();
diff --git a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp
index a7a81e9f0b..6cd730bd38 100644
--- a/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp
+++ b/tests/auto/network/ssl/qsslcertificate/tst_qsslcertificate.cpp
@@ -436,7 +436,7 @@ void tst_QSslCertificate::subjectAlternativeNames()
void tst_QSslCertificate::utf8SubjectNames()
{
QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert-ss-san-utf8.pem", QSsl::Pem,
- QSslCertificate::FixedString).first();
+ QSslCertificate::PatternSyntax::FixedString).first();
QVERIFY(!cert.isNull());
// O is "Heavy Metal Records" with heavy use of "decorations" like accents, umlauts etc.,
@@ -634,66 +634,66 @@ void tst_QSslCertificate::fromPath_qregularexpression_data()
QTest::addColumn<bool>("pemencoding");
QTest::addColumn<int>("numCerts");
- QTest::newRow("empty fixed pem") << QString() << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("empty fixed der") << QString() << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("empty regexp pem") << QString() << int(QSslCertificate::RegExp) << true << 0;
- QTest::newRow("empty regexp der") << QString() << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("empty wildcard pem") << QString() << int(QSslCertificate::Wildcard) << true << 0;
- QTest::newRow("empty wildcard der") << QString() << int(QSslCertificate::Wildcard) << false << 0;
- QTest::newRow("\"certificates\" fixed pem") << (testDataDir + "certificates") << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("\"certificates\" fixed der") << (testDataDir + "certificates") << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("\"certificates\" regexp pem") << (testDataDir + "certificates") << int(QSslCertificate::RegExp) << true << 0;
- QTest::newRow("\"certificates\" regexp der") << (testDataDir + "certificates") << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("\"certificates\" wildcard pem") << (testDataDir + "certificates") << int(QSslCertificate::Wildcard) << true << 0;
- QTest::newRow("\"certificates\" wildcard der") << (testDataDir + "certificates") << int(QSslCertificate::Wildcard) << false << 0;
- QTest::newRow("\"certificates/cert.pem\" fixed pem") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::FixedString) << true << 1;
- QTest::newRow("\"certificates/cert.pem\" fixed der") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("\"certificates/cert.pem\" regexp pem") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::RegExp) << true << 1;
- QTest::newRow("\"certificates/cert.pem\" regexp der") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("\"certificates/cert.pem\" wildcard pem") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::Wildcard) << true << 1;
- QTest::newRow("\"certificates/cert.pem\" wildcard der") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::Wildcard) << false << 0;
- QTest::newRow("\"certificates/*\" fixed pem") << (testDataDir + "certificates/*") << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("\"certificates/*\" fixed der") << (testDataDir + "certificates/*") << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("\"certificates/*\" regexp pem") << (testDataDir + "certificates/*") << int(QSslCertificate::RegExp) << true << 0;
- QTest::newRow("\"certificates/*\" regexp der") << (testDataDir + "certificates/*") << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("\"certificates/*\" wildcard pem") << (testDataDir + "certificates/*") << int(QSslCertificate::Wildcard) << true << 7;
- QTest::newRow("\"certificates/ca*\" wildcard pem") << (testDataDir + "certificates/ca*") << int(QSslCertificate::Wildcard) << true << 1;
- QTest::newRow("\"certificates/cert*\" wildcard pem") << (testDataDir + "certificates/cert*") << int(QSslCertificate::Wildcard) << true << 4;
- QTest::newRow("\"certificates/cert-[sure]*\" wildcard pem") << (testDataDir + "certificates/cert-[sure]*") << int(QSslCertificate::Wildcard) << true << 3;
- QTest::newRow("\"certificates/cert-[not]*\" wildcard pem") << (testDataDir + "certificates/cert-[not]*") << int(QSslCertificate::Wildcard) << true << 0;
- QTest::newRow("\"certificates/*\" wildcard der") << (testDataDir + "certificates/*") << int(QSslCertificate::Wildcard) << false << 2;
- QTest::newRow("\"c*/c*.pem\" fixed pem") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("\"c*/c*.pem\" fixed der") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("\"c*/c*.pem\" regexp pem") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::RegExp) << true << 0;
- QTest::newRow("\"c*/c*.pem\" regexp der") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("\"c*/c*.pem\" wildcard pem") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::Wildcard) << true << 5;
- QTest::newRow("\"c*/c*.pem\" wildcard der") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::Wildcard) << false << 0;
- QTest::newRow("\"d*/c*.pem\" fixed pem") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("\"d*/c*.pem\" fixed der") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("\"d*/c*.pem\" regexp pem") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::RegExp) << true << 0;
- QTest::newRow("\"d*/c*.pem\" regexp der") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("\"d*/c*.pem\" wildcard pem") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::Wildcard) << true << 0;
- QTest::newRow("\"d*/c*.pem\" wildcard der") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::Wildcard) << false << 0;
- QTest::newRow("\"c.*/c.*.pem\" fixed pem") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("\"c.*/c.*.pem\" fixed der") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("\"c.*/c.*.pem\" regexp pem") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::RegExp) << true << 5;
- QTest::newRow("\"c.*/c.*.pem\" regexp der") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("\"c.*/c.*.pem\" wildcard pem") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::Wildcard) << true << 0;
- QTest::newRow("\"c.*/c.*.pem\" wildcard der") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::Wildcard) << false << 0;
- QTest::newRow("\"d.*/c.*.pem\" fixed pem") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("\"d.*/c.*.pem\" fixed der") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::FixedString) << false << 0;
- QTest::newRow("\"d.*/c.*.pem\" regexp pem") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::RegExp) << true << 0;
- QTest::newRow("\"d.*/c.*.pem\" regexp der") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::RegExp) << false << 0;
- QTest::newRow("\"d.*/c.*.pem\" wildcard pem") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::Wildcard) << true << 0;
- QTest::newRow("\"d.*/c.*.pem\" wildcard der") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::Wildcard) << false << 0;
+ QTest::newRow("empty fixed pem") << QString() << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("empty fixed der") << QString() << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("empty regexp pem") << QString() << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0;
+ QTest::newRow("empty regexp der") << QString() << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("empty wildcard pem") << QString() << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0;
+ QTest::newRow("empty wildcard der") << QString() << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0;
+ QTest::newRow("\"certificates\" fixed pem") << (testDataDir + "certificates") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("\"certificates\" fixed der") << (testDataDir + "certificates") << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("\"certificates\" regexp pem") << (testDataDir + "certificates") << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0;
+ QTest::newRow("\"certificates\" regexp der") << (testDataDir + "certificates") << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("\"certificates\" wildcard pem") << (testDataDir + "certificates") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0;
+ QTest::newRow("\"certificates\" wildcard der") << (testDataDir + "certificates") << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0;
+ QTest::newRow("\"certificates/cert.pem\" fixed pem") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 1;
+ QTest::newRow("\"certificates/cert.pem\" fixed der") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("\"certificates/cert.pem\" regexp pem") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 1;
+ QTest::newRow("\"certificates/cert.pem\" regexp der") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("\"certificates/cert.pem\" wildcard pem") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 1;
+ QTest::newRow("\"certificates/cert.pem\" wildcard der") << (testDataDir + "certificates/cert.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0;
+ QTest::newRow("\"certificates/*\" fixed pem") << (testDataDir + "certificates/*") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("\"certificates/*\" fixed der") << (testDataDir + "certificates/*") << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("\"certificates/*\" regexp pem") << (testDataDir + "certificates/*") << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0;
+ QTest::newRow("\"certificates/*\" regexp der") << (testDataDir + "certificates/*") << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("\"certificates/*\" wildcard pem") << (testDataDir + "certificates/*") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 7;
+ QTest::newRow("\"certificates/ca*\" wildcard pem") << (testDataDir + "certificates/ca*") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 1;
+ QTest::newRow("\"certificates/cert*\" wildcard pem") << (testDataDir + "certificates/cert*") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 4;
+ QTest::newRow("\"certificates/cert-[sure]*\" wildcard pem") << (testDataDir + "certificates/cert-[sure]*") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 3;
+ QTest::newRow("\"certificates/cert-[not]*\" wildcard pem") << (testDataDir + "certificates/cert-[not]*") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0;
+ QTest::newRow("\"certificates/*\" wildcard der") << (testDataDir + "certificates/*") << int(QSslCertificate::PatternSyntax::Wildcard) << false << 2;
+ QTest::newRow("\"c*/c*.pem\" fixed pem") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("\"c*/c*.pem\" fixed der") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("\"c*/c*.pem\" regexp pem") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0;
+ QTest::newRow("\"c*/c*.pem\" regexp der") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("\"c*/c*.pem\" wildcard pem") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 5;
+ QTest::newRow("\"c*/c*.pem\" wildcard der") << (testDataDir + "c*/c*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0;
+ QTest::newRow("\"d*/c*.pem\" fixed pem") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("\"d*/c*.pem\" fixed der") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("\"d*/c*.pem\" regexp pem") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0;
+ QTest::newRow("\"d*/c*.pem\" regexp der") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("\"d*/c*.pem\" wildcard pem") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0;
+ QTest::newRow("\"d*/c*.pem\" wildcard der") << (testDataDir + "d*/c*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0;
+ QTest::newRow("\"c.*/c.*.pem\" fixed pem") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("\"c.*/c.*.pem\" fixed der") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("\"c.*/c.*.pem\" regexp pem") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 5;
+ QTest::newRow("\"c.*/c.*.pem\" regexp der") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("\"c.*/c.*.pem\" wildcard pem") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0;
+ QTest::newRow("\"c.*/c.*.pem\" wildcard der") << (testDataDir + "c.*/c.*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0;
+ QTest::newRow("\"d.*/c.*.pem\" fixed pem") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("\"d.*/c.*.pem\" fixed der") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::PatternSyntax::FixedString) << false << 0;
+ QTest::newRow("\"d.*/c.*.pem\" regexp pem") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << true << 0;
+ QTest::newRow("\"d.*/c.*.pem\" regexp der") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::PatternSyntax::RegularExpression) << false << 0;
+ QTest::newRow("\"d.*/c.*.pem\" wildcard pem") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 0;
+ QTest::newRow("\"d.*/c.*.pem\" wildcard der") << (testDataDir + "d.*/c.*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << false << 0;
#ifdef Q_OS_LINUX
- QTest::newRow("absolute path wildcard pem") << (testDataDir + "certificates/*.pem") << int(QSslCertificate::Wildcard) << true << 7;
+ QTest::newRow("absolute path wildcard pem") << (testDataDir + "certificates/*.pem") << int(QSslCertificate::PatternSyntax::Wildcard) << true << 7;
#endif
- QTest::newRow("trailing-whitespace") << (testDataDir + "more-certificates/trailing-whitespace.pem") << int(QSslCertificate::FixedString) << true << 1;
- QTest::newRow("no-ending-newline") << (testDataDir + "more-certificates/no-ending-newline.pem") << int(QSslCertificate::FixedString) << true << 1;
- QTest::newRow("malformed-just-begin") << (testDataDir + "more-certificates/malformed-just-begin.pem") << int(QSslCertificate::FixedString) << true << 0;
- QTest::newRow("malformed-just-begin-no-newline") << (testDataDir + "more-certificates/malformed-just-begin-no-newline.pem") << int(QSslCertificate::FixedString) << true << 0;
+ QTest::newRow("trailing-whitespace") << (testDataDir + "more-certificates/trailing-whitespace.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 1;
+ QTest::newRow("no-ending-newline") << (testDataDir + "more-certificates/no-ending-newline.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 1;
+ QTest::newRow("malformed-just-begin") << (testDataDir + "more-certificates/malformed-just-begin.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
+ QTest::newRow("malformed-just-begin-no-newline") << (testDataDir + "more-certificates/malformed-just-begin-no-newline.pem") << int(QSslCertificate::PatternSyntax::FixedString) << true << 0;
}
void tst_QSslCertificate::fromPath_qregularexpression()
@@ -795,7 +795,7 @@ void tst_QSslCertificate::certInfo()
"55:ba:e7:fb:95:5d:91";
QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
- QSslCertificate::FixedString).first();
+ QSslCertificate::PatternSyntax::FixedString).first();
QVERIFY(!cert.isNull());
QCOMPARE(cert.issuerInfo(QSslCertificate::Organization)[0], QString("CryptSoft Pty Ltd"));
@@ -852,7 +852,7 @@ void tst_QSslCertificate::certInfo()
void tst_QSslCertificate::certInfoQByteArray()
{
QSslCertificate cert = QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem,
- QSslCertificate::FixedString).first();
+ QSslCertificate::PatternSyntax::FixedString).first();
QVERIFY(!cert.isNull());
// in this test, check the bytearray variants before the enum variants to see if
@@ -904,7 +904,7 @@ void tst_QSslCertificate::nulInCN()
QSKIP("Generic QSslCertificatePrivate fails this test");
#endif
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/badguy-nul-cn.crt", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/badguy-nul-cn.crt", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QCOMPARE(certList.size(), 1);
const QSslCertificate &cert = certList.at(0);
@@ -923,7 +923,7 @@ void tst_QSslCertificate::nulInSan()
QSKIP("Generic QSslCertificatePrivate fails this test");
#endif
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/badguy-nul-san.crt", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/badguy-nul-san.crt", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QCOMPARE(certList.size(), 1);
const QSslCertificate &cert = certList.at(0);
@@ -943,7 +943,7 @@ void tst_QSslCertificate::nulInSan()
void tst_QSslCertificate::largeSerialNumber()
{
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-serial-number.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-serial-number.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QCOMPARE(certList.size(), 1);
@@ -955,7 +955,7 @@ void tst_QSslCertificate::largeSerialNumber()
void tst_QSslCertificate::largeExpirationDate() // QTBUG-12489
{
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-expiration-date.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-expiration-date.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QCOMPARE(certList.size(), 1);
@@ -968,7 +968,7 @@ void tst_QSslCertificate::largeExpirationDate() // QTBUG-12489
void tst_QSslCertificate::blacklistedCertificates()
{
- QList<QSslCertificate> blacklistedCerts = QSslCertificate::fromPath(testDataDir + "more-certificates/blacklisted*.pem", QSsl::Pem, QSslCertificate::Wildcard);
+ QList<QSslCertificate> blacklistedCerts = QSslCertificate::fromPath(testDataDir + "more-certificates/blacklisted*.pem", QSsl::Pem, QSslCertificate::PatternSyntax::Wildcard);
QVERIFY(blacklistedCerts.count() > 0);
for (int a = 0; a < blacklistedCerts.count(); a++) {
QVERIFY(blacklistedCerts.at(a).isBlacklisted());
@@ -977,15 +977,15 @@ void tst_QSslCertificate::blacklistedCertificates()
void tst_QSslCertificate::selfsignedCertificates()
{
- QVERIFY(QSslCertificate::fromPath(testDataDir + "certificates/cert-ss.pem", QSsl::Pem, QSslCertificate::FixedString).first().isSelfSigned());
- QVERIFY(!QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem, QSslCertificate::FixedString).first().isSelfSigned());
+ QVERIFY(QSslCertificate::fromPath(testDataDir + "certificates/cert-ss.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first().isSelfSigned());
+ QVERIFY(!QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first().isSelfSigned());
QVERIFY(!QSslCertificate().isSelfSigned());
}
void tst_QSslCertificate::toText()
{
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-expiration-date.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-expiration-date.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QCOMPARE(certList.size(), 1);
const QSslCertificate &cert = certList.at(0);
@@ -1027,7 +1027,7 @@ void tst_QSslCertificate::toText()
void tst_QSslCertificate::multipleCommonNames()
{
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/test-cn-two-cns-cert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/test-cn-two-cns-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QVERIFY(certList.count() > 0);
QStringList commonNames = certList[0].subjectInfo(QSslCertificate::CommonName);
@@ -1038,14 +1038,14 @@ void tst_QSslCertificate::multipleCommonNames()
void tst_QSslCertificate::subjectAndIssuerAttributes()
{
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/test-cn-with-drink-cert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/test-cn-with-drink-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QVERIFY(certList.count() > 0);
QList<QByteArray> attributes = certList[0].subjectInfoAttributes();
QVERIFY(attributes.contains(QByteArray("favouriteDrink")));
attributes.clear();
- certList = QSslCertificate::fromPath(testDataDir + "more-certificates/natwest-banking.pem", QSsl::Pem, QSslCertificate::FixedString);
+ certList = QSslCertificate::fromPath(testDataDir + "more-certificates/natwest-banking.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QVERIFY(certList.count() > 0);
QByteArray shortName("1.3.6.1.4.1.311.60.2.1.3");
@@ -1080,17 +1080,17 @@ void tst_QSslCertificate::verify()
errors.clear();
// Verify a valid cert signed by a CA
- QList<QSslCertificate> caCerts = QSslCertificate::fromPath(testDataDir + "verify-certs/cacert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QList<QSslCertificate> caCerts = QSslCertificate::fromPath(testDataDir + "verify-certs/cacert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QSslSocket::addDefaultCaCertificate(caCerts.first());
- toVerify = QSslCertificate::fromPath(testDataDir + "verify-certs/test-ocsp-good-cert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ toVerify = QSslCertificate::fromPath(testDataDir + "verify-certs/test-ocsp-good-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
errors = QSslCertificate::verify(toVerify);
VERIFY_VERBOSE(errors.count() == 0);
errors.clear();
// Test a blacklisted certificate
- toVerify = QSslCertificate::fromPath(testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ toVerify = QSslCertificate::fromPath(testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
errors = QSslCertificate::verify(toVerify);
bool foundBlack = false;
foreach (const QSslError &error, errors) {
@@ -1103,7 +1103,7 @@ void tst_QSslCertificate::verify()
errors.clear();
// This one is expired and untrusted
- toVerify = QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-serial-number.pem", QSsl::Pem, QSslCertificate::FixedString);
+ toVerify = QSslCertificate::fromPath(testDataDir + "more-certificates/cert-large-serial-number.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
errors = QSslCertificate::verify(toVerify);
VERIFY_VERBOSE(errors.contains(QSslError(QSslError::SelfSignedCertificate, toVerify[0])));
VERIFY_VERBOSE(errors.contains(QSslError(QSslError::CertificateExpired, toVerify[0])));
@@ -1111,15 +1111,15 @@ void tst_QSslCertificate::verify()
toVerify.clear();
// This one is signed by a valid cert, but the signer is not a valid CA
- toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-not-ca-cert.pem", QSsl::Pem, QSslCertificate::FixedString).first();
- toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-ocsp-good-cert.pem", QSsl::Pem, QSslCertificate::FixedString).first();
+ toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-not-ca-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first();
+ toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-ocsp-good-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first();
errors = QSslCertificate::verify(toVerify);
VERIFY_VERBOSE(errors.contains(QSslError(QSslError::InvalidCaCertificate, toVerify[1])));
toVerify.clear();
// This one is signed by a valid cert, and the signer is a valid CA
- toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-is-ca-cert.pem", QSsl::Pem, QSslCertificate::FixedString).first();
- toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-ca-cert.pem", QSsl::Pem, QSslCertificate::FixedString).first();
+ toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-is-ca-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first();
+ toVerify << QSslCertificate::fromPath(testDataDir + "verify-certs/test-intermediate-ca-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString).first();
errors = QSslCertificate::verify(toVerify);
VERIFY_VERBOSE(errors.count() == 0);
@@ -1149,7 +1149,7 @@ QString tst_QSslCertificate::toString(const QList<QSslError>& errors)
void tst_QSslCertificate::extensions()
{
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "more-certificates/natwest-banking.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "more-certificates/natwest-banking.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QVERIFY(certList.count() > 0);
QSslCertificate cert = certList[0];
@@ -1247,7 +1247,7 @@ void tst_QSslCertificate::extensions()
void tst_QSslCertificate::extensionsCritical()
{
QList<QSslCertificate> certList =
- QSslCertificate::fromPath(testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ QSslCertificate::fromPath(testDataDir + "verify-certs/test-addons-mozilla-org-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QVERIFY(certList.count() > 0);
QSslCertificate cert = certList[0];
@@ -1368,12 +1368,12 @@ void tst_QSslCertificate::version_data()
QTest::newRow("null certificate") << QSslCertificate() << QByteArray();
QList<QSslCertificate> certs;
- certs << QSslCertificate::fromPath(testDataDir + "verify-certs/test-ocsp-good-cert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ certs << QSslCertificate::fromPath(testDataDir + "verify-certs/test-ocsp-good-cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QTest::newRow("v3 certificate") << certs.first() << QByteArrayLiteral("3");
certs.clear();
- certs << QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem, QSslCertificate::FixedString);
+ certs << QSslCertificate::fromPath(testDataDir + "certificates/cert.pem", QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QTest::newRow("v1 certificate") << certs.first() << QByteArrayLiteral("1");
}
@@ -1410,7 +1410,7 @@ void tst_QSslCertificate::pkcs12()
QVERIFY(ok);
f.close();
- QList<QSslCertificate> leafCert = QSslCertificate::fromPath(testDataDir + QLatin1String("pkcs12/leaf.crt"), QSsl::Pem, QSslCertificate::FixedString);
+ QList<QSslCertificate> leafCert = QSslCertificate::fromPath(testDataDir + QLatin1String("pkcs12/leaf.crt"), QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QVERIFY(!leafCert.isEmpty());
QCOMPARE(cert, leafCert.first());
@@ -1425,7 +1425,7 @@ void tst_QSslCertificate::pkcs12()
QVERIFY(!leafKey.isNull());
QCOMPARE(key, leafKey);
- QList<QSslCertificate> caCert = QSslCertificate::fromPath(testDataDir + QLatin1String("pkcs12/inter.crt"), QSsl::Pem, QSslCertificate::FixedString);
+ QList<QSslCertificate> caCert = QSslCertificate::fromPath(testDataDir + QLatin1String("pkcs12/inter.crt"), QSsl::Pem, QSslCertificate::PatternSyntax::FixedString);
QVERIFY(!caCert.isEmpty());
QVERIFY(!caCerts.isEmpty());
diff --git a/tests/auto/opengl/qgl/tst_qgl.cpp b/tests/auto/opengl/qgl/tst_qgl.cpp
new file mode 100644
index 0000000000..d860caaa37
--- /dev/null
+++ b/tests/auto/opengl/qgl/tst_qgl.cpp
@@ -0,0 +1,2525 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <qcoreapplication.h>
+#include <qdebug.h>
+#include <qgl.h>
+#include <qglpixelbuffer.h>
+#include <qglframebufferobject.h>
+#include <qglcolormap.h>
+#include <qpaintengine.h>
+#include <qpainterpath.h>
+#include <qopenglfunctions.h>
+#include <qopenglframebufferobject.h>
+#include <qopenglpaintdevice.h>
+
+#include <QGraphicsView>
+#include <QGraphicsProxyWidget>
+#include <QVBoxLayout>
+
+#ifdef QT_BUILD_INTERNAL
+#include <qpa/qplatformpixmap.h>
+#include <QtOpenGL/private/qgl_p.h>
+#include <QtGui/private/qimage_p.h>
+#include <QtGui/private/qimagepixmapcleanuphooks_p.h>
+#include <QtGui/private/qopenglextensions_p.h>
+#endif
+
+class tst_QGL : public QObject
+{
+Q_OBJECT
+
+public:
+ tst_QGL();
+ virtual ~tst_QGL();
+
+ static void initMain();
+
+private slots:
+ void initTestCase();
+ void getSetCheck();
+#ifdef QT_BUILD_INTERNAL
+ void qglContextDefaultBindTexture();
+ void openGLVersionCheck();
+ void shareRegister();
+ void textureCleanup();
+#endif
+ void partialGLWidgetUpdates_data();
+ void partialGLWidgetUpdates();
+ void glWidgetWithAlpha();
+ void glWidgetRendering();
+ void glFBOSimpleRendering();
+ void glFBORendering();
+ void currentFboSync();
+ void multipleFBOInterleavedRendering();
+ void glFBOUseInGLWidget();
+ void glPBufferRendering();
+ void glWidgetReparent();
+ void glWidgetRenderPixmap();
+ void colormap();
+ void fboFormat();
+ void testDontCrashOnDanglingResources();
+ void replaceClipping();
+ void clipTest();
+ void destroyFBOAfterContext();
+ void threadImages();
+ void nullRectCrash();
+ void graphicsViewClipping();
+ void extensions();
+};
+
+tst_QGL::tst_QGL()
+{
+}
+
+tst_QGL::~tst_QGL()
+{
+}
+
+void tst_QGL::initMain()
+{
+ QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
+}
+
+void tst_QGL::initTestCase()
+{
+ QGLWidget glWidget;
+ if (!glWidget.isValid())
+ QSKIP("QGL is not supported on the test system");
+}
+
+class MyGLContext : public QGLContext
+{
+public:
+ MyGLContext(const QGLFormat& format) : QGLContext(format) {}
+ bool windowCreated() const { return QGLContext::windowCreated(); }
+ void setWindowCreated(bool on) { QGLContext::setWindowCreated(on); }
+ bool initialized() const { return QGLContext::initialized(); }
+ void setInitialized(bool on) { QGLContext::setInitialized(on); }
+};
+
+class MyGLWidget : public QGLWidget
+{
+public:
+ MyGLWidget() : QGLWidget() {}
+ bool autoBufferSwap() const { return QGLWidget::autoBufferSwap(); }
+ void setAutoBufferSwap(bool on) { QGLWidget::setAutoBufferSwap(on); }
+};
+
+static int appDefaultDepth()
+{
+ static int depth = 0;
+ if (depth == 0) {
+ QPixmap pm(1, 1);
+ depth = pm.depth();
+ }
+ return depth;
+}
+
+// Using INT_MIN and INT_MAX will cause failures on systems
+// where "int" is 64-bit, so use the explicit values instead.
+#define TEST_INT_MIN (-2147483647 - 1)
+#define TEST_INT_MAX 2147483647
+
+// Testing get/set functions
+void tst_QGL::getSetCheck()
+{
+ QGLFormat obj1;
+ // int QGLFormat::depthBufferSize()
+ // void QGLFormat::setDepthBufferSize(int)
+ QCOMPARE(-1, obj1.depthBufferSize());
+ obj1.setDepthBufferSize(0);
+ QCOMPARE(0, obj1.depthBufferSize());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size -2147483648");
+ obj1.setDepthBufferSize(TEST_INT_MIN);
+ QCOMPARE(0, obj1.depthBufferSize()); // Makes no sense with a negative buffer size
+ obj1.setDepthBufferSize(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setDepthBufferSize: Cannot set negative depth buffer size -1");
+ obj1.setDepthBufferSize(-1);
+ QCOMPARE(3, obj1.depthBufferSize());
+ obj1.setDepthBufferSize(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.depthBufferSize());
+
+ // int QGLFormat::accumBufferSize()
+ // void QGLFormat::setAccumBufferSize(int)
+ QCOMPARE(-1, obj1.accumBufferSize());
+ obj1.setAccumBufferSize(0);
+ QCOMPARE(0, obj1.accumBufferSize());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size -2147483648");
+ obj1.setAccumBufferSize(TEST_INT_MIN);
+ QCOMPARE(0, obj1.accumBufferSize()); // Makes no sense with a negative buffer size
+ obj1.setAccumBufferSize(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAccumBufferSize: Cannot set negative accumulate buffer size -1");
+ obj1.setAccumBufferSize(-1);
+ QCOMPARE(3, obj1.accumBufferSize());
+ obj1.setAccumBufferSize(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.accumBufferSize());
+
+ // int QGLFormat::redBufferSize()
+ // void QGLFormat::setRedBufferSize(int)
+ QCOMPARE(-1, obj1.redBufferSize());
+ obj1.setRedBufferSize(0);
+ QCOMPARE(0, obj1.redBufferSize());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setRedBufferSize: Cannot set negative red buffer size -2147483648");
+ obj1.setRedBufferSize(TEST_INT_MIN);
+ QCOMPARE(0, obj1.redBufferSize()); // Makes no sense with a negative buffer size
+ obj1.setRedBufferSize(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setRedBufferSize: Cannot set negative red buffer size -1");
+ obj1.setRedBufferSize(-1);
+ QCOMPARE(3, obj1.redBufferSize());
+ obj1.setRedBufferSize(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.redBufferSize());
+
+ // int QGLFormat::greenBufferSize()
+ // void QGLFormat::setGreenBufferSize(int)
+ QCOMPARE(-1, obj1.greenBufferSize());
+ obj1.setGreenBufferSize(0);
+ QCOMPARE(0, obj1.greenBufferSize());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setGreenBufferSize: Cannot set negative green buffer size -2147483648");
+ obj1.setGreenBufferSize(TEST_INT_MIN);
+ QCOMPARE(0, obj1.greenBufferSize()); // Makes no sense with a negative buffer size
+ obj1.setGreenBufferSize(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setGreenBufferSize: Cannot set negative green buffer size -1");
+ obj1.setGreenBufferSize(-1);
+ QCOMPARE(3, obj1.greenBufferSize());
+ obj1.setGreenBufferSize(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.greenBufferSize());
+
+ // int QGLFormat::blueBufferSize()
+ // void QGLFormat::setBlueBufferSize(int)
+ QCOMPARE(-1, obj1.blueBufferSize());
+ obj1.setBlueBufferSize(0);
+ QCOMPARE(0, obj1.blueBufferSize());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size -2147483648");
+ obj1.setBlueBufferSize(TEST_INT_MIN);
+ QCOMPARE(0, obj1.blueBufferSize()); // Makes no sense with a negative buffer size
+ obj1.setBlueBufferSize(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setBlueBufferSize: Cannot set negative blue buffer size -1");
+ obj1.setBlueBufferSize(-1);
+ QCOMPARE(3, obj1.blueBufferSize());
+ obj1.setBlueBufferSize(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.blueBufferSize());
+
+ // int QGLFormat::alphaBufferSize()
+ // void QGLFormat::setAlphaBufferSize(int)
+ QCOMPARE(-1, obj1.alphaBufferSize());
+ QCOMPARE(false, obj1.alpha());
+ QVERIFY(!obj1.testOption(QGL::AlphaChannel));
+ QVERIFY(obj1.testOption(QGL::NoAlphaChannel));
+ obj1.setAlphaBufferSize(1);
+ QCOMPARE(true, obj1.alpha()); // setAlphaBufferSize() enables alpha.
+ QCOMPARE(1, obj1.alphaBufferSize());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -2147483648");
+ obj1.setAlphaBufferSize(TEST_INT_MIN);
+ QCOMPARE(1, obj1.alphaBufferSize()); // Makes no sense with a negative buffer size
+ obj1.setAlphaBufferSize(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setAlphaBufferSize: Cannot set negative alpha buffer size -1");
+ obj1.setAlphaBufferSize(-1);
+ QCOMPARE(3, obj1.alphaBufferSize());
+ obj1.setAlphaBufferSize(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.alphaBufferSize());
+
+ // int QGLFormat::stencilBufferSize()
+ // void QGLFormat::setStencilBufferSize(int)
+ QCOMPARE(-1, obj1.stencilBufferSize());
+ obj1.setStencilBufferSize(1);
+ QCOMPARE(1, obj1.stencilBufferSize());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -2147483648");
+ obj1.setStencilBufferSize(TEST_INT_MIN);
+ QCOMPARE(1, obj1.stencilBufferSize()); // Makes no sense with a negative buffer size
+ obj1.setStencilBufferSize(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setStencilBufferSize: Cannot set negative stencil buffer size -1");
+ obj1.setStencilBufferSize(-1);
+ QCOMPARE(3, obj1.stencilBufferSize());
+ obj1.setStencilBufferSize(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.stencilBufferSize());
+
+ // bool QGLFormat::sampleBuffers()
+ // void QGLFormat::setSampleBuffers(bool)
+ QCOMPARE(false, obj1.sampleBuffers());
+ QVERIFY(!obj1.testOption(QGL::SampleBuffers));
+ QVERIFY(obj1.testOption(QGL::NoSampleBuffers));
+
+ obj1.setSampleBuffers(false);
+ QCOMPARE(false, obj1.sampleBuffers());
+ QVERIFY(obj1.testOption(QGL::NoSampleBuffers));
+ obj1.setSampleBuffers(true);
+ QCOMPARE(true, obj1.sampleBuffers());
+ QVERIFY(obj1.testOption(QGL::SampleBuffers));
+
+ // int QGLFormat::samples()
+ // void QGLFormat::setSamples(int)
+ QCOMPARE(-1, obj1.samples());
+ obj1.setSamples(0);
+ QCOMPARE(0, obj1.samples());
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setSamples: Cannot have negative number of samples per pixel -2147483648");
+ obj1.setSamples(TEST_INT_MIN);
+ QCOMPARE(0, obj1.samples()); // Makes no sense with a negative sample size
+ obj1.setSamples(3);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setSamples: Cannot have negative number of samples per pixel -1");
+ obj1.setSamples(-1);
+ QCOMPARE(3, obj1.samples());
+ obj1.setSamples(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.samples());
+
+ // int QGLFormat::swapInterval()
+ // void QGLFormat::setSwapInterval(int)
+ QCOMPARE(-1, obj1.swapInterval());
+ obj1.setSwapInterval(0);
+ QCOMPARE(0, obj1.swapInterval());
+ obj1.setSwapInterval(TEST_INT_MIN);
+ QCOMPARE(TEST_INT_MIN, obj1.swapInterval());
+ obj1.setSwapInterval(-1);
+ QCOMPARE(-1, obj1.swapInterval());
+ obj1.setSwapInterval(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.swapInterval());
+
+ // bool QGLFormat::doubleBuffer()
+ // void QGLFormat::setDoubleBuffer(bool)
+ QCOMPARE(true, obj1.doubleBuffer());
+ QVERIFY(obj1.testOption(QGL::DoubleBuffer));
+ QVERIFY(!obj1.testOption(QGL::SingleBuffer));
+ obj1.setDoubleBuffer(false);
+ QCOMPARE(false, obj1.doubleBuffer());
+ QVERIFY(!obj1.testOption(QGL::DoubleBuffer));
+ QVERIFY(obj1.testOption(QGL::SingleBuffer));
+ obj1.setDoubleBuffer(true);
+ QCOMPARE(true, obj1.doubleBuffer());
+ QVERIFY(obj1.testOption(QGL::DoubleBuffer));
+ QVERIFY(!obj1.testOption(QGL::SingleBuffer));
+
+ // bool QGLFormat::depth()
+ // void QGLFormat::setDepth(bool)
+ QCOMPARE(true, obj1.depth());
+ QVERIFY(obj1.testOption(QGL::DepthBuffer));
+ QVERIFY(!obj1.testOption(QGL::NoDepthBuffer));
+ obj1.setDepth(false);
+ QCOMPARE(false, obj1.depth());
+ QVERIFY(!obj1.testOption(QGL::DepthBuffer));
+ QVERIFY(obj1.testOption(QGL::NoDepthBuffer));
+ obj1.setDepth(true);
+ QCOMPARE(true, obj1.depth());
+ QVERIFY(obj1.testOption(QGL::DepthBuffer));
+ QVERIFY(!obj1.testOption(QGL::NoDepthBuffer));
+
+ // bool QGLFormat::rgba()
+ // void QGLFormat::setRgba(bool)
+ QCOMPARE(true, obj1.rgba());
+ QVERIFY(obj1.testOption(QGL::Rgba));
+ QVERIFY(!obj1.testOption(QGL::ColorIndex));
+ obj1.setRgba(false);
+ QCOMPARE(false, obj1.rgba());
+ QVERIFY(!obj1.testOption(QGL::Rgba));
+ QVERIFY(obj1.testOption(QGL::ColorIndex));
+ obj1.setRgba(true);
+ QCOMPARE(true, obj1.rgba());
+ QVERIFY(obj1.testOption(QGL::Rgba));
+ QVERIFY(!obj1.testOption(QGL::ColorIndex));
+
+ // bool QGLFormat::alpha()
+ // void QGLFormat::setAlpha(bool)
+ QVERIFY(obj1.testOption(QGL::AlphaChannel));
+ QVERIFY(!obj1.testOption(QGL::NoAlphaChannel));
+ obj1.setAlpha(false);
+ QCOMPARE(false, obj1.alpha());
+ QVERIFY(!obj1.testOption(QGL::AlphaChannel));
+ QVERIFY(obj1.testOption(QGL::NoAlphaChannel));
+ obj1.setAlpha(true);
+ QCOMPARE(true, obj1.alpha());
+ QVERIFY(obj1.testOption(QGL::AlphaChannel));
+ QVERIFY(!obj1.testOption(QGL::NoAlphaChannel));
+
+ // bool QGLFormat::accum()
+ // void QGLFormat::setAccum(bool)
+ obj1.setAccumBufferSize(0);
+ QCOMPARE(false, obj1.accum());
+ QVERIFY(!obj1.testOption(QGL::AccumBuffer));
+ QVERIFY(obj1.testOption(QGL::NoAccumBuffer));
+ obj1.setAccum(false);
+ QCOMPARE(false, obj1.accum());
+ QVERIFY(!obj1.testOption(QGL::AccumBuffer));
+ QVERIFY(obj1.testOption(QGL::NoAccumBuffer));
+ obj1.setAccum(true);
+ QCOMPARE(true, obj1.accum());
+ QVERIFY(obj1.testOption(QGL::AccumBuffer));
+ QVERIFY(!obj1.testOption(QGL::NoAccumBuffer));
+
+ // bool QGLFormat::stencil()
+ // void QGLFormat::setStencil(bool)
+ QCOMPARE(true, obj1.stencil());
+ QVERIFY(obj1.testOption(QGL::StencilBuffer));
+ QVERIFY(!obj1.testOption(QGL::NoStencilBuffer));
+ obj1.setStencil(false);
+ QCOMPARE(false, obj1.stencil());
+ QVERIFY(!obj1.testOption(QGL::StencilBuffer));
+ QVERIFY(obj1.testOption(QGL::NoStencilBuffer));
+ obj1.setStencil(true);
+ QCOMPARE(true, obj1.stencil());
+ QVERIFY(obj1.testOption(QGL::StencilBuffer));
+ QVERIFY(!obj1.testOption(QGL::NoStencilBuffer));
+
+ // bool QGLFormat::stereo()
+ // void QGLFormat::setStereo(bool)
+ QCOMPARE(false, obj1.stereo());
+ QVERIFY(!obj1.testOption(QGL::StereoBuffers));
+ QVERIFY(obj1.testOption(QGL::NoStereoBuffers));
+ obj1.setStereo(false);
+ QCOMPARE(false, obj1.stereo());
+ QVERIFY(!obj1.testOption(QGL::StereoBuffers));
+ QVERIFY(obj1.testOption(QGL::NoStereoBuffers));
+ obj1.setStereo(true);
+ QCOMPARE(true, obj1.stereo());
+ QVERIFY(obj1.testOption(QGL::StereoBuffers));
+ QVERIFY(!obj1.testOption(QGL::NoStereoBuffers));
+
+ // bool QGLFormat::directRendering()
+ // void QGLFormat::setDirectRendering(bool)
+ QCOMPARE(true, obj1.directRendering());
+ QVERIFY(obj1.testOption(QGL::DirectRendering));
+ QVERIFY(!obj1.testOption(QGL::IndirectRendering));
+ obj1.setDirectRendering(false);
+ QCOMPARE(false, obj1.directRendering());
+ QVERIFY(!obj1.testOption(QGL::DirectRendering));
+ QVERIFY(obj1.testOption(QGL::IndirectRendering));
+ obj1.setDirectRendering(true);
+ QCOMPARE(true, obj1.directRendering());
+ QVERIFY(obj1.testOption(QGL::DirectRendering));
+ QVERIFY(!obj1.testOption(QGL::IndirectRendering));
+
+ // bool QGLFormat::overlay()
+ // void QGLFormat::setOverlay(bool)
+ QCOMPARE(false, obj1.hasOverlay());
+ QVERIFY(!obj1.testOption(QGL::HasOverlay));
+ QVERIFY(obj1.testOption(QGL::NoOverlay));
+ obj1.setOverlay(false);
+ QCOMPARE(false, obj1.hasOverlay());
+ QVERIFY(!obj1.testOption(QGL::HasOverlay));
+ QVERIFY(obj1.testOption(QGL::NoOverlay));
+ obj1.setOverlay(true);
+ QCOMPARE(true, obj1.hasOverlay());
+ QVERIFY(obj1.testOption(QGL::HasOverlay));
+ QVERIFY(!obj1.testOption(QGL::NoOverlay));
+
+ // int QGLFormat::plane()
+ // void QGLFormat::setPlane(int)
+ QCOMPARE(0, obj1.plane());
+ obj1.setPlane(0);
+ QCOMPARE(0, obj1.plane());
+ obj1.setPlane(TEST_INT_MIN);
+ QCOMPARE(TEST_INT_MIN, obj1.plane());
+ obj1.setPlane(TEST_INT_MAX);
+ QCOMPARE(TEST_INT_MAX, obj1.plane());
+
+ // int QGLFormat::major/minorVersion()
+ // void QGLFormat::setVersion(int, int)
+ QCOMPARE(obj1.majorVersion(), 2);
+ QCOMPARE(obj1.minorVersion(), 0);
+ obj1.setVersion(3, 2);
+ QCOMPARE(obj1.majorVersion(), 3);
+ QCOMPARE(obj1.minorVersion(), 2);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 0.1");
+ obj1.setVersion(0, 1);
+ QCOMPARE(obj1.majorVersion(), 3);
+ QCOMPARE(obj1.minorVersion(), 2);
+ QTest::ignoreMessage(QtWarningMsg, "QGLFormat::setVersion: Cannot set zero or negative version number 3.-1");
+ obj1.setVersion(3, -1);
+ QCOMPARE(obj1.majorVersion(), 3);
+ QCOMPARE(obj1.minorVersion(), 2);
+ obj1.setVersion(TEST_INT_MAX, TEST_INT_MAX - 1);
+ QCOMPARE(obj1.majorVersion(), TEST_INT_MAX);
+ QCOMPARE(obj1.minorVersion(), TEST_INT_MAX - 1);
+
+
+ // operator== and operator!= for QGLFormat
+ QGLFormat format1;
+ QGLFormat format2;
+
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+ format1.setDoubleBuffer(false);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setDoubleBuffer(false);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setDepthBufferSize(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setDepthBufferSize(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setAccumBufferSize(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setAccumBufferSize(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setRedBufferSize(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setRedBufferSize(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setGreenBufferSize(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setGreenBufferSize(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setBlueBufferSize(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setBlueBufferSize(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setAlphaBufferSize(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setAlphaBufferSize(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setStencilBufferSize(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setStencilBufferSize(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setSamples(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setSamples(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setSwapInterval(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setSwapInterval(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setPlane(8);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setPlane(8);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setVersion(3, 2);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setVersion(3, 2);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setProfile(QGLFormat::CoreProfile);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setProfile(QGLFormat::CoreProfile);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ format1.setOption(QGL::NoDeprecatedFunctions);
+ QVERIFY(!(format1 == format2));
+ QVERIFY(format1 != format2);
+ format2.setOption(QGL::NoDeprecatedFunctions);
+ QCOMPARE(format1, format2);
+ QVERIFY(!(format1 != format2));
+
+ // Copy constructor and assignment for QGLFormat.
+ QGLFormat format3(format1);
+ QGLFormat format4;
+ QCOMPARE(format1, format3);
+ QVERIFY(format1 != format4);
+ format4 = format1;
+ QCOMPARE(format1, format4);
+
+ // Check that modifying a copy doesn't affect the original.
+ format3.setRedBufferSize(16);
+ format4.setPlane(16);
+ QCOMPARE(format1.redBufferSize(), 8);
+ QCOMPARE(format1.plane(), 8);
+
+ // Check the QGLFormat constructor that takes an option list.
+ QGLFormat format5
+ (QGL::DepthBuffer | QGL::StereoBuffers | QGL::ColorIndex, 3);
+ QVERIFY(format5.depth());
+ QVERIFY(format5.stereo());
+ QVERIFY(format5.doubleBuffer()); // From defaultFormat()
+ QVERIFY(!format5.hasOverlay()); // From defaultFormat()
+ QVERIFY(!format5.rgba());
+ QCOMPARE(format5.plane(), 3);
+
+ // The default format should be the same as QGLFormat().
+ QCOMPARE(QGLFormat::defaultFormat(), QGLFormat());
+
+ // Modify the default format and check that it was changed.
+ QGLFormat::setDefaultFormat(format1);
+ QCOMPARE(QGLFormat::defaultFormat(), format1);
+
+ // Restore the default format.
+ QGLFormat::setDefaultFormat(QGLFormat());
+ QCOMPARE(QGLFormat::defaultFormat(), QGLFormat());
+
+ // Check the default overlay format's expected values.
+ QGLFormat overlay(QGLFormat::defaultOverlayFormat());
+ QCOMPARE(overlay.depthBufferSize(), -1);
+ QCOMPARE(overlay.accumBufferSize(), -1);
+ QCOMPARE(overlay.redBufferSize(), -1);
+ QCOMPARE(overlay.greenBufferSize(), -1);
+ QCOMPARE(overlay.blueBufferSize(), -1);
+ QCOMPARE(overlay.alphaBufferSize(), -1);
+ QCOMPARE(overlay.samples(), -1);
+ QCOMPARE(overlay.swapInterval(), -1);
+ QCOMPARE(overlay.plane(), 1);
+ QVERIFY(!overlay.sampleBuffers());
+ QVERIFY(!overlay.doubleBuffer());
+ QVERIFY(!overlay.depth());
+ QVERIFY(!overlay.rgba());
+ QVERIFY(!overlay.alpha());
+ QVERIFY(!overlay.accum());
+ QVERIFY(!overlay.stencil());
+ QVERIFY(!overlay.stereo());
+ QVERIFY(overlay.directRendering()); // Only option that should be on.
+ QVERIFY(!overlay.hasOverlay()); // Overlay doesn't need an overlay!
+
+ // Modify the default overlay format and check that it was changed.
+ QGLFormat::setDefaultOverlayFormat(format1);
+ QCOMPARE(QGLFormat::defaultOverlayFormat(), format1);
+
+ // Restore the default overlay format.
+ QGLFormat::setDefaultOverlayFormat(overlay);
+ QCOMPARE(QGLFormat::defaultOverlayFormat(), overlay);
+
+ MyGLContext obj2(obj1);
+ // bool QGLContext::windowCreated()
+ // void QGLContext::setWindowCreated(bool)
+ obj2.setWindowCreated(false);
+ QCOMPARE(false, obj2.windowCreated());
+ obj2.setWindowCreated(true);
+ QCOMPARE(true, obj2.windowCreated());
+
+ // bool QGLContext::initialized()
+ // void QGLContext::setInitialized(bool)
+ obj2.setInitialized(false);
+ QCOMPARE(false, obj2.initialized());
+ obj2.setInitialized(true);
+ QCOMPARE(true, obj2.initialized());
+
+ MyGLWidget obj3;
+ // bool QGLWidget::autoBufferSwap()
+ // void QGLWidget::setAutoBufferSwap(bool)
+ obj3.setAutoBufferSwap(false);
+ QCOMPARE(false, obj3.autoBufferSwap());
+ obj3.setAutoBufferSwap(true);
+ QCOMPARE(true, obj3.autoBufferSwap());
+}
+
+#ifdef QT_BUILD_INTERNAL
+QT_BEGIN_NAMESPACE
+extern QGLFormat::OpenGLVersionFlags qOpenGLVersionFlagsFromString(const QString &versionString);
+QT_END_NAMESPACE
+#endif
+
+#ifdef QT_BUILD_INTERNAL
+void tst_QGL::openGLVersionCheck()
+{
+ QString versionString;
+ QGLFormat::OpenGLVersionFlags expectedFlag;
+ QGLFormat::OpenGLVersionFlags versionFlag;
+
+ versionString = "1.1 Irix 6.5";
+ expectedFlag = QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "1.2 Microsoft";
+ expectedFlag = QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "1.2.1";
+ expectedFlag = QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "1.3 NVIDIA";
+ expectedFlag = QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "1.4";
+ expectedFlag = QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "1.5 NVIDIA";
+ expectedFlag = QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "2.0.2 NVIDIA 87.62";
+ expectedFlag = QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "2.1 NVIDIA";
+ expectedFlag = QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "2.1";
+ expectedFlag = QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "OpenGL ES-CM 1.0 ATI";
+ expectedFlag = QGLFormat::OpenGL_ES_Common_Version_1_0 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "OpenGL ES-CL 1.0 ATI";
+ expectedFlag = QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "OpenGL ES-CM 1.1 ATI";
+ expectedFlag = QGLFormat::OpenGL_ES_Common_Version_1_1 | QGLFormat::OpenGL_ES_CommonLite_Version_1_1 | QGLFormat::OpenGL_ES_Common_Version_1_0 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "OpenGL ES-CL 1.1 ATI";
+ expectedFlag = QGLFormat::OpenGL_ES_CommonLite_Version_1_1 | QGLFormat::OpenGL_ES_CommonLite_Version_1_0;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "OpenGL ES 2.0 ATI";
+ expectedFlag = QGLFormat::OpenGL_ES_Version_2_0;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ versionString = "3.0";
+ expectedFlag = QGLFormat::OpenGL_Version_3_0 | QGLFormat::OpenGL_Version_2_1 | QGLFormat::OpenGL_Version_2_0 | QGLFormat::OpenGL_Version_1_5 | QGLFormat::OpenGL_Version_1_4 | QGLFormat::OpenGL_Version_1_3 | QGLFormat::OpenGL_Version_1_2 | QGLFormat::OpenGL_Version_1_1;
+ versionFlag = qOpenGLVersionFlagsFromString(versionString);
+ QCOMPARE(versionFlag, expectedFlag);
+
+ QGLWidget glWidget;
+ glWidget.show();
+ glWidget.makeCurrent();
+
+ // This is unfortunately the only test we can make on the actual openGLVersionFlags()
+ // However, the complicated parts are in openGLVersionFlags(const QString &versionString)
+ // tested above
+
+#if defined(QT_OPENGL_ES_2)
+ QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0);
+#else
+ if (QOpenGLContext::currentContext()->isOpenGLES())
+ QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0);
+ else
+ QVERIFY(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_1);
+#endif //defined(QT_OPENGL_ES_2)
+}
+#endif //QT_BUILD_INTERNAL
+
+static bool fuzzyComparePixels(const QRgb testPixel, const QRgb refPixel, const char* file, int line, int x = -1, int y = -1)
+{
+ static int maxFuzz = 1;
+ static bool maxFuzzSet = false;
+
+ // On 16 bpp systems, we need to allow for more fuzz:
+ if (!maxFuzzSet) {
+ maxFuzzSet = true;
+ if (appDefaultDepth() < 24)
+ maxFuzz = 32;
+ }
+
+ int redFuzz = qAbs(qRed(testPixel) - qRed(refPixel));
+ int greenFuzz = qAbs(qGreen(testPixel) - qGreen(refPixel));
+ int blueFuzz = qAbs(qBlue(testPixel) - qBlue(refPixel));
+ int alphaFuzz = qAbs(qAlpha(testPixel) - qAlpha(refPixel));
+
+ if (refPixel != 0 && testPixel == 0) {
+ QString msg;
+ if (x >= 0) {
+ msg = QString("Test pixel [%1, %2] is null (black) when it should be (%3,%4,%5,%6)")
+ .arg(x).arg(y)
+ .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
+ } else {
+ msg = QString("Test pixel is null (black) when it should be (%2,%3,%4,%5)")
+ .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
+ }
+
+ QTest::qFail(msg.toLatin1(), file, line);
+ return false;
+ }
+
+ if (redFuzz > maxFuzz || greenFuzz > maxFuzz || blueFuzz > maxFuzz || alphaFuzz > maxFuzz) {
+ QString msg;
+
+ if (x >= 0)
+ msg = QString("Pixel [%1,%2]: ").arg(x).arg(y);
+ else
+ msg = QString("Pixel ");
+
+ msg += QString("Max fuzz (%1) exceeded: (%2,%3,%4,%5) vs (%6,%7,%8,%9)")
+ .arg(maxFuzz)
+ .arg(qRed(testPixel)).arg(qGreen(testPixel)).arg(qBlue(testPixel)).arg(qAlpha(testPixel))
+ .arg(qRed(refPixel)).arg(qGreen(refPixel)).arg(qBlue(refPixel)).arg(qAlpha(refPixel));
+ QTest::qFail(msg.toLatin1(), file, line);
+ return false;
+ }
+ return true;
+}
+
+static void fuzzyCompareImages(const QImage &testImage, const QImage &referenceImage, const char* file, int line)
+{
+ QCOMPARE(testImage.width(), referenceImage.width());
+ QCOMPARE(testImage.height(), referenceImage.height());
+
+ for (int y = 0; y < testImage.height(); y++) {
+ for (int x = 0; x < testImage.width(); x++) {
+ if (!fuzzyComparePixels(testImage.pixel(x, y), referenceImage.pixel(x, y), file, line, x, y)) {
+ // Might as well save the images for easier debugging:
+ referenceImage.save("referenceImage.png");
+ testImage.save("testImage.png");
+ return;
+ }
+ }
+ }
+}
+
+#define QFUZZY_COMPARE_IMAGES(A,B) \
+ fuzzyCompareImages(A, B, __FILE__, __LINE__)
+
+#define QFUZZY_COMPARE_PIXELS(A,B) \
+ fuzzyComparePixels(A, B, __FILE__, __LINE__)
+
+class UnclippedWidget : public QWidget
+{
+public:
+ bool painted;
+
+ UnclippedWidget()
+ : painted(false)
+ {
+ }
+
+ void paintEvent(QPaintEvent *)
+ {
+ QPainter p(this);
+ p.fillRect(rect().adjusted(-1000, -1000, 1000, 1000), Qt::black);
+
+ painted = true;
+ }
+};
+
+void tst_QGL::graphicsViewClipping()
+{
+ const int size = 64;
+ UnclippedWidget *widget = new UnclippedWidget;
+ widget->setFixedSize(size, size);
+
+ QGraphicsScene scene;
+
+ scene.addWidget(widget)->setPos(0, 0);
+
+ QGraphicsView view(&scene);
+ // Use Qt::Tool as fully decorated windows have a minimum width of 160 on Windows.
+ view.setWindowFlags(view.windowFlags() | Qt::Tool);
+ view.setBackgroundBrush(Qt::white);
+ view.resize(2*size, 2*size);
+
+ QGLWidget *viewport = new QGLWidget;
+ view.setViewport(viewport);
+ view.show();
+ qApp->setActiveWindow(&view);
+
+ if (!viewport->isValid())
+ return;
+
+ scene.setSceneRect(view.viewport()->rect());
+
+ QVERIFY(QTest::qWaitForWindowExposed(view.viewport()->windowHandle()));
+ #ifdef Q_OS_MAC
+ // The black rectangle jumps from the center to the upper left for some reason.
+ QTest::qWait(100);
+ #endif
+
+ QTRY_VERIFY(widget->painted);
+
+ QImage image = viewport->grabFrameBuffer();
+ QImage expected = image;
+
+ QPainter p(&expected);
+ p.fillRect(expected.rect(), Qt::white);
+ p.fillRect(QRect(0, 0, size, size), Qt::black);
+ p.end();
+
+ QFUZZY_COMPARE_IMAGES(image, expected);
+}
+
+void tst_QGL::partialGLWidgetUpdates_data()
+{
+ QTest::addColumn<bool>("doubleBufferedContext");
+ QTest::addColumn<bool>("autoFillBackground");
+ QTest::addColumn<bool>("supportsPartialUpdates");
+
+ QTest::newRow("Double buffered context") << true << true << false;
+ QTest::newRow("Double buffered context without auto-fill background") << true << false << false;
+ QTest::newRow("Single buffered context") << false << true << false;
+ QTest::newRow("Single buffered context without auto-fill background") << false << false << true;
+}
+
+void tst_QGL::partialGLWidgetUpdates()
+{
+ QFETCH(bool, doubleBufferedContext);
+ QFETCH(bool, autoFillBackground);
+ QFETCH(bool, supportsPartialUpdates);
+
+ class MyGLWidget : public QGLWidget
+ {
+ public:
+ QRegion paintEventRegion;
+ void paintEvent(QPaintEvent *e)
+ {
+ paintEventRegion = e->region();
+ }
+ };
+
+ QGLFormat format = QGLFormat::defaultFormat();
+ format.setDoubleBuffer(doubleBufferedContext);
+ QGLFormat::setDefaultFormat(format);
+
+ MyGLWidget widget;
+ widget.setFixedSize(150, 150);
+ widget.setAutoFillBackground(autoFillBackground);
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+ QCoreApplication::processEvents(); // Process all queued paint events
+
+ if (widget.format().doubleBuffer() != doubleBufferedContext)
+ QSKIP("Platform does not support requested format");
+
+ widget.paintEventRegion = QRegion();
+ widget.repaint(50, 50, 50, 50);
+
+ if (supportsPartialUpdates)
+ QCOMPARE(widget.paintEventRegion, QRegion(50, 50, 50, 50));
+ else
+ QCOMPARE(widget.paintEventRegion, QRegion(widget.rect()));
+}
+
+
+// This tests that rendering to a QGLPBuffer using QPainter works.
+void tst_QGL::glPBufferRendering()
+{
+ if (!QGLPixelBuffer::hasOpenGLPbuffers())
+ QSKIP("QGLPixelBuffer not supported on this platform");
+
+ QGLPixelBuffer* pbuf = new QGLPixelBuffer(128, 128);
+
+ QPainter p;
+ bool begun = p.begin(pbuf);
+ QVERIFY(begun);
+
+ QPaintEngine::Type engineType = p.paintEngine()->type();
+ QVERIFY(engineType == QPaintEngine::OpenGL || engineType == QPaintEngine::OpenGL2);
+
+ p.fillRect(0, 0, 128, 128, Qt::red);
+ p.fillRect(32, 32, 64, 64, Qt::blue);
+ p.end();
+
+ QImage fb = pbuf->toImage();
+ delete pbuf;
+
+ QImage reference(128, 128, fb.format());
+ p.begin(&reference);
+ p.fillRect(0, 0, 128, 128, Qt::red);
+ p.fillRect(32, 32, 64, 64, Qt::blue);
+ p.end();
+
+ QFUZZY_COMPARE_IMAGES(fb, reference);
+}
+
+void tst_QGL::glWidgetWithAlpha()
+{
+ QGLWidget* w = new QGLWidget(QGLFormat(QGL::AlphaChannel));
+ w->show();
+ QVERIFY(QTest::qWaitForWindowExposed(w));
+
+ delete w;
+}
+
+
+void qt_opengl_draw_test_pattern(QPainter* painter, int width, int height)
+{
+ QPainterPath intersectingPath;
+ intersectingPath.moveTo(0, 0);
+ intersectingPath.lineTo(100, 0);
+ intersectingPath.lineTo(0, 100);
+ intersectingPath.lineTo(100, 100);
+ intersectingPath.closeSubpath();
+
+ QPainterPath trianglePath;
+ trianglePath.moveTo(50, 0);
+ trianglePath.lineTo(100, 100);
+ trianglePath.lineTo(0, 100);
+ trianglePath.closeSubpath();
+
+ painter->setTransform(QTransform()); // reset xform
+ painter->fillRect(-1, -1, width+2, height+2, Qt::red); // Background
+ painter->translate(14, 14);
+ painter->fillPath(intersectingPath, Qt::blue); // Test stencil buffer works
+ painter->translate(128, 0);
+ painter->setClipPath(trianglePath); // Test depth buffer works
+ painter->setTransform(QTransform()); // reset xform ready for fill
+ painter->fillRect(-1, -1, width+2, height+2, Qt::green);
+}
+
+void qt_opengl_check_test_pattern(const QImage& img)
+{
+ // As we're doing more than trivial painting, we can't just compare to
+ // an image rendered with raster. Instead, we sample at well-defined
+ // test-points:
+ QFUZZY_COMPARE_PIXELS(img.pixel(39, 64), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(img.pixel(89, 64), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(img.pixel(64, 39), QColor(Qt::blue).rgb());
+ QFUZZY_COMPARE_PIXELS(img.pixel(64, 89), QColor(Qt::blue).rgb());
+
+ QFUZZY_COMPARE_PIXELS(img.pixel(167, 39), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(img.pixel(217, 39), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(img.pixel(192, 64), QColor(Qt::green).rgb());
+}
+
+class GLWidget : public QGLWidget
+{
+public:
+ GLWidget(QWidget* p = 0)
+ : QGLWidget(p), beginOk(false), engineType(QPaintEngine::MaxUser) {}
+ bool beginOk;
+ QPaintEngine::Type engineType;
+ void paintGL()
+ {
+ QPainter p;
+ beginOk = p.begin(this);
+ QPaintEngine* pe = p.paintEngine();
+ engineType = pe->type();
+
+ qt_opengl_draw_test_pattern(&p, width(), height());
+
+ // No p.end() or swap buffers, should be done automatically
+ }
+
+};
+
+void tst_QGL::glWidgetRendering()
+{
+ GLWidget w;
+ w.resize(256, 128);
+ w.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ QVERIFY(w.beginOk);
+ QVERIFY(w.engineType == QPaintEngine::OpenGL || w.engineType == QPaintEngine::OpenGL2);
+
+#if defined(Q_OS_QNX)
+ // glReadPixels reads from the back buffer. On QNX the buffer is not preserved
+ // after a buffer swap. This is why we have to swap the buffer explicitly before calling
+ // grabFrameBuffer to retrieve the content of the front buffer.
+ w.swapBuffers();
+#endif
+ QImage fb = w.grabFrameBuffer(false);
+ qt_opengl_check_test_pattern(fb);
+}
+
+void tst_QGL::glFBOSimpleRendering()
+{
+ if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QGLFramebufferObject not supported on this platform");
+
+ QGLWidget glw;
+ glw.makeCurrent();
+
+ // No multisample with combined depth/stencil attachment:
+ QGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QGLFramebufferObject::NoAttachment);
+
+ QGLFramebufferObject *fbo = new QGLFramebufferObject(200, 100, fboFormat);
+
+ fbo->bind();
+
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glClearColor(1.0, 0.0, 0.0, 1.0);
+ funcs->glClear(GL_COLOR_BUFFER_BIT);
+ funcs->glFinish();
+
+ QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
+ QImage reference(fb.size(), QImage::Format_RGB32);
+ reference.fill(0xffff0000);
+
+ QFUZZY_COMPARE_IMAGES(fb, reference);
+
+ delete fbo;
+}
+
+// NOTE: This tests that CombinedDepthStencil attachment works by assuming the
+// GL2 engine is being used and is implemented the same way as it was when
+// this autotest was written. If this is not the case, there may be some
+// false-positives: I.e. The test passes when either the depth or stencil
+// buffer is actually missing. But that's probably ok anyway.
+void tst_QGL::glFBORendering()
+{
+#if defined(Q_OS_QNX)
+ QSKIP("Reading the QGLFramebufferObject is unsupported on this platform");
+#endif
+ if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QGLFramebufferObject not supported on this platform");
+
+ QGLWidget glw;
+ glw.makeCurrent();
+
+ // No multisample with combined depth/stencil attachment:
+ QGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+ // Don't complicate things by using NPOT:
+ QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);
+
+ if (fbo->attachment() != QGLFramebufferObject::CombinedDepthStencil) {
+ delete fbo;
+ QSKIP("FBOs missing combined depth~stencil support");
+ }
+
+ QPainter fboPainter;
+ bool painterBegun = fboPainter.begin(fbo);
+ QVERIFY(painterBegun);
+
+ qt_opengl_draw_test_pattern(&fboPainter, fbo->width(), fbo->height());
+
+ fboPainter.end();
+
+ QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
+ delete fbo;
+
+ qt_opengl_check_test_pattern(fb);
+}
+
+class QOpenGLFramebufferObjectPaintDevice : public QOpenGLPaintDevice
+{
+public:
+ QOpenGLFramebufferObjectPaintDevice(int width, int height)
+ : QOpenGLPaintDevice(width, height)
+ , m_fbo(width, height, QOpenGLFramebufferObject::CombinedDepthStencil)
+ {
+ }
+
+ void ensureActiveTarget()
+ {
+ m_fbo.bind();
+ }
+
+ QImage toImage() const
+ {
+ return m_fbo.toImage();
+ }
+
+private:
+ QOpenGLFramebufferObject m_fbo;
+};
+
+void tst_QGL::currentFboSync()
+{
+ if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QGLFramebufferObject not supported on this platform");
+
+#if defined(Q_OS_QNX)
+ QSKIP("Reading the QGLFramebufferObject is unsupported on this platform");
+#endif
+
+ QGLWidget glw;
+ glw.makeCurrent();
+
+ // For some reason we offer inter-operatibility between QGL and QOpenGL
+ // paint engines. (?!) Let's check if the two engines can be used to perform
+ // drawing in turns on different targets within the same context.
+
+ {
+ QGLFramebufferObject fbo1(256, 256, QGLFramebufferObject::CombinedDepthStencil);
+
+ QOpenGLFramebufferObjectPaintDevice fbo2(256, 256);
+
+ QImage sourceImage(256, 256, QImage::Format_ARGB32_Premultiplied);
+ QPainter sourcePainter(&sourceImage);
+ qt_opengl_draw_test_pattern(&sourcePainter, 256, 256);
+
+ QPainter fbo1Painter(&fbo1);
+
+ QPainter fbo2Painter(&fbo2);
+ fbo2Painter.drawImage(0, 0, sourceImage);
+ fbo2Painter.end();
+
+ QImage fbo2Image = fbo2.toImage();
+
+ fbo1Painter.drawImage(0, 0, sourceImage);
+ fbo1Painter.end();
+
+ QGLFramebufferObject::bindDefault();
+
+ // Convert the QGLFBO's result since QOpenGLFBO uses a wider
+ // variety of possible return formats.
+ QCOMPARE(fbo1.toImage().convertToFormat(fbo2Image.format()), fbo2Image);
+ }
+
+ {
+ QGLFramebufferObject fbo1(512, 512, QGLFramebufferObject::CombinedDepthStencil);
+
+ QOpenGLFramebufferObjectPaintDevice fbo2(256, 256);
+
+ QImage sourceImage(256, 256, QImage::Format_ARGB32_Premultiplied);
+ QPainter sourcePainter(&sourceImage);
+ qt_opengl_draw_test_pattern(&sourcePainter, 256, 256);
+
+ QPainter fbo2Painter(&fbo2);
+ fbo2Painter.drawImage(0, 0, sourceImage);
+ QImage fbo2Image1 = fbo2.toImage();
+ fbo2Painter.fillRect(0, 0, 256, 256, Qt::white);
+
+ QPainter fbo1Painter(&fbo1);
+ fbo1Painter.drawImage(0, 0, sourceImage);
+ fbo1Painter.end();
+
+ // check that the OpenGL paint engine now knows it needs to sync
+ fbo2Painter.drawImage(0, 0, sourceImage);
+ QImage fbo2Image2 = fbo2.toImage();
+
+ fbo2Painter.end();
+
+ QCOMPARE(fbo2Image1, fbo2Image2);
+ }
+}
+
+// Tests multiple QPainters active on different FBOs at the same time, with
+// interleaving painting. Performance-wise, this is sub-optimal, but it still
+// has to work flawlessly
+void tst_QGL::multipleFBOInterleavedRendering()
+{
+ if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QGLFramebufferObject not supported on this platform");
+
+ QGLWidget glw;
+ glw.makeCurrent();
+
+ // No multisample with combined depth/stencil attachment:
+ QGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+ QGLFramebufferObject *fbo1 = new QGLFramebufferObject(256, 128, fboFormat);
+ QGLFramebufferObject *fbo2 = new QGLFramebufferObject(256, 128, fboFormat);
+ QGLFramebufferObject *fbo3 = new QGLFramebufferObject(256, 128, fboFormat);
+
+ if ( (fbo1->attachment() != QGLFramebufferObject::CombinedDepthStencil) ||
+ (fbo2->attachment() != QGLFramebufferObject::CombinedDepthStencil) ||
+ (fbo3->attachment() != QGLFramebufferObject::CombinedDepthStencil) )
+ {
+ delete fbo1;
+ delete fbo2;
+ delete fbo3;
+ QSKIP("FBOs missing combined depth~stencil support");
+ }
+
+ QPainter fbo1Painter;
+ QPainter fbo2Painter;
+ QPainter fbo3Painter;
+
+ QVERIFY(fbo1Painter.begin(fbo1));
+ QVERIFY(fbo2Painter.begin(fbo2));
+ QVERIFY(fbo3Painter.begin(fbo3));
+
+ // Confirm we're using the GL2 engine, as interleaved rendering isn't supported
+ // on the GL1 engine:
+ if (fbo1Painter.paintEngine()->type() != QPaintEngine::OpenGL2)
+ QSKIP("Interleaved GL rendering requires OpenGL 2.0 or higher");
+
+ QPainterPath intersectingPath;
+ intersectingPath.moveTo(0, 0);
+ intersectingPath.lineTo(100, 0);
+ intersectingPath.lineTo(0, 100);
+ intersectingPath.lineTo(100, 100);
+ intersectingPath.closeSubpath();
+
+ QPainterPath trianglePath;
+ trianglePath.moveTo(50, 0);
+ trianglePath.lineTo(100, 100);
+ trianglePath.lineTo(0, 100);
+ trianglePath.closeSubpath();
+
+ fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::red); // Background
+ fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::green); // Background
+ fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::blue); // Background
+
+ fbo1Painter.translate(14, 14);
+ fbo2Painter.translate(14, 14);
+ fbo3Painter.translate(14, 14);
+
+ fbo1Painter.fillPath(intersectingPath, Qt::blue); // Test stencil buffer works
+ fbo2Painter.fillPath(intersectingPath, Qt::red); // Test stencil buffer works
+ fbo3Painter.fillPath(intersectingPath, Qt::green); // Test stencil buffer works
+
+ fbo1Painter.translate(128, 0);
+ fbo2Painter.translate(128, 0);
+ fbo3Painter.translate(128, 0);
+
+ fbo1Painter.setClipPath(trianglePath);
+ fbo2Painter.setClipPath(trianglePath);
+ fbo3Painter.setClipPath(trianglePath);
+
+ fbo1Painter.setTransform(QTransform()); // reset xform
+ fbo2Painter.setTransform(QTransform()); // reset xform
+ fbo3Painter.setTransform(QTransform()); // reset xform
+
+ fbo1Painter.fillRect(0, 0, fbo1->width(), fbo1->height(), Qt::green);
+ fbo2Painter.fillRect(0, 0, fbo2->width(), fbo2->height(), Qt::blue);
+ fbo3Painter.fillRect(0, 0, fbo3->width(), fbo3->height(), Qt::red);
+
+ fbo1Painter.end();
+ fbo2Painter.end();
+ fbo3Painter.end();
+
+ QImage fb1 = fbo1->toImage().convertToFormat(QImage::Format_RGB32);
+ QImage fb2 = fbo2->toImage().convertToFormat(QImage::Format_RGB32);
+ QImage fb3 = fbo3->toImage().convertToFormat(QImage::Format_RGB32);
+ delete fbo1;
+ delete fbo2;
+ delete fbo3;
+
+ // As we're doing more than trivial painting, we can't just compare to
+ // an image rendered with raster. Instead, we sample at well-defined
+ // test-points:
+ QFUZZY_COMPARE_PIXELS(fb1.pixel(39, 64), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(fb1.pixel(89, 64), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 39), QColor(Qt::blue).rgb());
+ QFUZZY_COMPARE_PIXELS(fb1.pixel(64, 89), QColor(Qt::blue).rgb());
+ QFUZZY_COMPARE_PIXELS(fb1.pixel(167, 39), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(fb1.pixel(217, 39), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(fb1.pixel(192, 64), QColor(Qt::green).rgb());
+
+ QFUZZY_COMPARE_PIXELS(fb2.pixel(39, 64), QColor(Qt::green).rgb());
+ QFUZZY_COMPARE_PIXELS(fb2.pixel(89, 64), QColor(Qt::green).rgb());
+ QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 39), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(fb2.pixel(64, 89), QColor(Qt::red).rgb());
+ QFUZZY_COMPARE_PIXELS(fb2.pixel(167, 39), QColor(Qt::green).rgb());
+ QFUZZY_COMPARE_PIXELS(fb2.pixel(217, 39), QColor(Qt::green).rgb());
+ QFUZZY_COMPARE_PIXELS(fb2.pixel(192, 64), QColor(Qt::blue).rgb());
+
+ QFUZZY_COMPARE_PIXELS(fb3.pixel(39, 64), QColor(Qt::blue).rgb());
+ QFUZZY_COMPARE_PIXELS(fb3.pixel(89, 64), QColor(Qt::blue).rgb());
+ QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 39), QColor(Qt::green).rgb());
+ QFUZZY_COMPARE_PIXELS(fb3.pixel(64, 89), QColor(Qt::green).rgb());
+ QFUZZY_COMPARE_PIXELS(fb3.pixel(167, 39), QColor(Qt::blue).rgb());
+ QFUZZY_COMPARE_PIXELS(fb3.pixel(217, 39), QColor(Qt::blue).rgb());
+ QFUZZY_COMPARE_PIXELS(fb3.pixel(192, 64), QColor(Qt::red).rgb());
+}
+
+class FBOUseInGLWidget : public QGLWidget
+{
+public:
+ bool widgetPainterBeginOk;
+ bool fboPainterBeginOk;
+ QImage fboImage;
+protected:
+ void paintEvent(QPaintEvent*)
+ {
+ QPainter widgetPainter;
+ widgetPainterBeginOk = widgetPainter.begin(this);
+ QGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QGLFramebufferObject::NoAttachment);
+ QGLFramebufferObject *fbo = new QGLFramebufferObject(100, 100, fboFormat);
+
+ QPainter fboPainter;
+ fboPainterBeginOk = fboPainter.begin(fbo);
+ fboPainter.fillRect(-1, -1, 130, 130, Qt::red);
+ fboPainter.end();
+ fboImage = fbo->toImage();
+
+ widgetPainter.fillRect(-1, -1, width()+2, height()+2, Qt::blue);
+
+ delete fbo;
+ }
+
+};
+
+void tst_QGL::glFBOUseInGLWidget()
+{
+ if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QGLFramebufferObject not supported on this platform");
+
+ FBOUseInGLWidget w;
+ w.resize(100, 100);
+ w.showNormal();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+
+ QVERIFY(w.widgetPainterBeginOk);
+ QVERIFY(w.fboPainterBeginOk);
+
+#if defined(Q_OS_QNX)
+ // glReadPixels reads from the back buffer. On QNX the buffer is not preserved
+ // after a buffer swap. This is why we have to swap the buffer explicitly before calling
+ // grabFrameBuffer to retrieve the content of the front buffer
+ w.swapBuffers();
+#endif
+
+ QImage widgetFB = w.grabFrameBuffer(false);
+ QImage widgetReference(widgetFB.size(), widgetFB.format());
+ widgetReference.fill(0xff0000ff);
+ QFUZZY_COMPARE_IMAGES(widgetFB, widgetReference);
+
+ QImage fboReference(w.fboImage.size(), w.fboImage.format());
+ fboReference.fill(0xffff0000);
+ QFUZZY_COMPARE_IMAGES(w.fboImage, fboReference);
+}
+
+void tst_QGL::glWidgetReparent()
+{
+ // Try it as a top-level first:
+ GLWidget *widget = new GLWidget;
+ widget->setObjectName(QStringLiteral("glWidget1"));
+ widget->setGeometry(0, 0, 200, 30);
+ widget->show();
+
+ QWidget grandParentWidget;
+ grandParentWidget.setObjectName(QStringLiteral("grandParentWidget"));
+ grandParentWidget.setPalette(Qt::blue);
+ QVBoxLayout grandParentLayout(&grandParentWidget);
+
+ QWidget parentWidget(&grandParentWidget);
+ parentWidget.setObjectName(QStringLiteral("parentWidget"));
+ grandParentLayout.addWidget(&parentWidget);
+ parentWidget.setPalette(Qt::green);
+ parentWidget.setAutoFillBackground(true);
+ QVBoxLayout parentLayout(&parentWidget);
+
+ grandParentWidget.setGeometry(0, 100, 200, 200);
+ grandParentWidget.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(widget));
+ QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
+
+ QVERIFY(parentWidget.children().count() == 1); // The layout
+
+ // Now both widgets should be created & shown, time to re-parent:
+ parentLayout.addWidget(widget);
+
+ QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
+
+ QVERIFY(parentWidget.children().count() == 2); // Layout & glwidget
+ QVERIFY(parentWidget.children().contains(widget));
+ QTRY_VERIFY(widget->height() > 30);
+
+ delete widget;
+
+ QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
+
+ QVERIFY(parentWidget.children().count() == 1); // The layout
+
+ // Now do pretty much the same thing, but don't show the
+ // widget first:
+ widget = new GLWidget;
+ widget->setObjectName(QStringLiteral("glWidget2"));
+ parentLayout.addWidget(widget);
+
+ QVERIFY(QTest::qWaitForWindowExposed(&grandParentWidget));
+
+ QVERIFY(parentWidget.children().count() == 2); // Layout & glwidget
+ QVERIFY(parentWidget.children().contains(widget));
+ QVERIFY(widget->height() > 30);
+
+ delete widget;
+}
+
+class RenderPixmapWidget : public QGLWidget
+{
+protected:
+ void initializeGL() {
+ // Set some gl state:
+ QOpenGLContext::currentContext()->functions()->glClearColor(1.0, 0.0, 0.0, 1.0);
+ }
+
+ void paintGL() {
+ QOpenGLContext::currentContext()->functions()->glClear(GL_COLOR_BUFFER_BIT);
+ }
+};
+
+void tst_QGL::glWidgetRenderPixmap()
+{
+ RenderPixmapWidget *w = new RenderPixmapWidget;
+
+ QSize pmSize = QSize(100, 100);
+ QPixmap pm = w->renderPixmap(pmSize.width(), pmSize.height(), false);
+
+ delete w;
+
+ QImage fb = pm.toImage().convertToFormat(QImage::Format_RGB32);
+ QImage reference(pmSize, QImage::Format_RGB32);
+ reference.fill(0xffff0000);
+
+ QFUZZY_COMPARE_IMAGES(fb, reference);
+}
+
+class ColormapExtended : public QGLColormap
+{
+public:
+ ColormapExtended() {}
+
+ Qt::HANDLE handle() { return QGLColormap::handle(); }
+ void setHandle(Qt::HANDLE handle) { QGLColormap::setHandle(handle); }
+};
+
+void tst_QGL::colormap()
+{
+ // Check the properties of the default empty colormap.
+ QGLColormap cmap1;
+ QVERIFY(cmap1.isEmpty());
+ QCOMPARE(cmap1.size(), 0);
+ QCOMPARE(cmap1.entryRgb(0), QRgb(0));
+ QCOMPARE(cmap1.entryRgb(-1), QRgb(0));
+ QCOMPARE(cmap1.entryRgb(100), QRgb(0));
+ QVERIFY(!cmap1.entryColor(0).isValid());
+ QVERIFY(!cmap1.entryColor(-1).isValid());
+ QVERIFY(!cmap1.entryColor(100).isValid());
+ QCOMPARE(cmap1.find(qRgb(255, 0, 0)), -1);
+ QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), -1);
+
+ // Set an entry and re-test.
+ cmap1.setEntry(56, qRgb(255, 0, 0));
+ // The colormap is still considered "empty" even though it
+ // has entries in it now. The isEmpty() method is used to
+ // detect when the colormap is in use by a GL widget,
+ // not to detect when it is empty!
+ QVERIFY(cmap1.isEmpty());
+ QCOMPARE(cmap1.size(), 256);
+ QCOMPARE(cmap1.entryRgb(0), QRgb(0));
+ QVERIFY(cmap1.entryColor(0) == QColor(0, 0, 0, 255));
+ QVERIFY(cmap1.entryRgb(56) == qRgb(255, 0, 0));
+ QVERIFY(cmap1.entryColor(56) == QColor(255, 0, 0, 255));
+ QCOMPARE(cmap1.find(qRgb(255, 0, 0)), 56);
+ QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), 56);
+
+ // Set some more entries.
+ static QRgb const colors[] = {
+ qRgb(255, 0, 0),
+ qRgb(0, 255, 0),
+ qRgb(255, 255, 255),
+ qRgb(0, 0, 255),
+ qRgb(0, 0, 0)
+ };
+ cmap1.setEntry(57, QColor(0, 255, 0));
+ cmap1.setEntries(3, colors + 2, 58);
+ cmap1.setEntries(5, colors, 251);
+ int idx;
+ for (idx = 0; idx < 5; ++idx) {
+ QVERIFY(cmap1.entryRgb(56 + idx) == colors[idx]);
+ QVERIFY(cmap1.entryColor(56 + idx) == QColor(colors[idx]));
+ QVERIFY(cmap1.entryRgb(251 + idx) == colors[idx]);
+ QVERIFY(cmap1.entryColor(251 + idx) == QColor(colors[idx]));
+ }
+ QCOMPARE(cmap1.size(), 256);
+
+ // Perform color lookups.
+ QCOMPARE(cmap1.find(qRgb(255, 0, 0)), 56);
+ QCOMPARE(cmap1.find(qRgb(0, 0, 0)), 60); // Actually finds 0, 0, 0, 255.
+ QCOMPARE(cmap1.find(qRgba(0, 0, 0, 0)), 0);
+ QCOMPARE(cmap1.find(qRgb(0, 255, 0)), 57);
+ QCOMPARE(cmap1.find(qRgb(255, 255, 255)), 58);
+ QCOMPARE(cmap1.find(qRgb(0, 0, 255)), 59);
+ QCOMPARE(cmap1.find(qRgb(140, 0, 0)), -1);
+ QCOMPARE(cmap1.find(qRgb(0, 140, 0)), -1);
+ QCOMPARE(cmap1.find(qRgb(0, 0, 140)), -1);
+ QCOMPARE(cmap1.find(qRgb(64, 0, 0)), -1);
+ QCOMPARE(cmap1.find(qRgb(0, 64, 0)), -1);
+ QCOMPARE(cmap1.find(qRgb(0, 0, 64)), -1);
+ QCOMPARE(cmap1.findNearest(qRgb(255, 0, 0)), 56);
+ QCOMPARE(cmap1.findNearest(qRgb(0, 0, 0)), 60);
+ QCOMPARE(cmap1.findNearest(qRgba(0, 0, 0, 0)), 0);
+ QCOMPARE(cmap1.findNearest(qRgb(0, 255, 0)), 57);
+ QCOMPARE(cmap1.findNearest(qRgb(255, 255, 255)), 58);
+ QCOMPARE(cmap1.findNearest(qRgb(0, 0, 255)), 59);
+ QCOMPARE(cmap1.findNearest(qRgb(140, 0, 0)), 56);
+ QCOMPARE(cmap1.findNearest(qRgb(0, 140, 0)), 57);
+ QCOMPARE(cmap1.findNearest(qRgb(0, 0, 140)), 59);
+ QCOMPARE(cmap1.findNearest(qRgb(64, 0, 0)), 0);
+ QCOMPARE(cmap1.findNearest(qRgb(0, 64, 0)), 0);
+ QCOMPARE(cmap1.findNearest(qRgb(0, 0, 64)), 0);
+
+ // Make some copies of the colormap and check that they are the same.
+ QGLColormap cmap2(cmap1);
+ QGLColormap cmap3;
+ cmap3 = cmap1;
+ QVERIFY(cmap2.isEmpty());
+ QVERIFY(cmap3.isEmpty());
+ QCOMPARE(cmap2.size(), 256);
+ QCOMPARE(cmap3.size(), 256);
+ for (idx = 0; idx < 256; ++idx) {
+ QCOMPARE(cmap1.entryRgb(idx), cmap2.entryRgb(idx));
+ QCOMPARE(cmap1.entryRgb(idx), cmap3.entryRgb(idx));
+ }
+
+ // Modify an entry in one of the copies and recheck the original.
+ cmap2.setEntry(45, qRgb(255, 0, 0));
+ for (idx = 0; idx < 256; ++idx) {
+ if (idx != 45)
+ QCOMPARE(cmap1.entryRgb(idx), cmap2.entryRgb(idx));
+ else
+ QCOMPARE(cmap2.entryRgb(45), qRgb(255, 0, 0));
+ QCOMPARE(cmap1.entryRgb(idx), cmap3.entryRgb(idx));
+ }
+
+ // Check that setting the handle will cause isEmpty() to work right.
+ ColormapExtended cmap4;
+ cmap4.setEntry(56, qRgb(255, 0, 0));
+ QVERIFY(cmap4.isEmpty());
+ QCOMPARE(cmap4.size(), 256);
+ cmap4.setHandle(Qt::HANDLE(42));
+ QCOMPARE(cmap4.handle(), Qt::HANDLE(42));
+ QVERIFY(!cmap4.isEmpty());
+ QCOMPARE(cmap4.size(), 256);
+}
+
+#ifndef GL_TEXTURE_3D
+#define GL_TEXTURE_3D 0x806F
+#endif
+
+#ifndef GL_RGB16
+#define GL_RGB16 0x8054
+#endif
+
+void tst_QGL::fboFormat()
+{
+ // Check the initial conditions.
+ QGLFramebufferObjectFormat format1;
+ QCOMPARE(format1.samples(), 0);
+ QCOMPARE(format1.attachment(), QGLFramebufferObject::NoAttachment);
+ QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_2D));
+ int expectedFormat =
+#ifdef QT_OPENGL_ES_2
+ GL_RGBA;
+#else
+ QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? GL_RGBA : GL_RGBA8;
+#endif
+ QCOMPARE(int(format1.internalTextureFormat()), expectedFormat);
+
+ // Modify the values and re-check.
+ format1.setSamples(8);
+ format1.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ format1.setTextureTarget(GL_TEXTURE_3D);
+ format1.setInternalTextureFormat(GL_RGB16);
+ QCOMPARE(format1.samples(), 8);
+ QCOMPARE(format1.attachment(), QGLFramebufferObject::CombinedDepthStencil);
+ QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_3D));
+ QCOMPARE(int(format1.internalTextureFormat()), int(GL_RGB16));
+
+ // Make copies and check that they are the same.
+ QGLFramebufferObjectFormat format2(format1);
+ QGLFramebufferObjectFormat format3;
+ QCOMPARE(format2.samples(), 8);
+ QCOMPARE(format2.attachment(), QGLFramebufferObject::CombinedDepthStencil);
+ QCOMPARE(int(format2.textureTarget()), int(GL_TEXTURE_3D));
+ QCOMPARE(int(format2.internalTextureFormat()), int(GL_RGB16));
+ format3 = format1;
+ QCOMPARE(format3.samples(), 8);
+ QCOMPARE(format3.attachment(), QGLFramebufferObject::CombinedDepthStencil);
+ QCOMPARE(int(format3.textureTarget()), int(GL_TEXTURE_3D));
+ QCOMPARE(int(format3.internalTextureFormat()), int(GL_RGB16));
+
+ // Modify the copies and check that the original is unchanged.
+ format2.setSamples(9);
+ format3.setTextureTarget(GL_TEXTURE_2D);
+ QCOMPARE(format1.samples(), 8);
+ QCOMPARE(format1.attachment(), QGLFramebufferObject::CombinedDepthStencil);
+ QCOMPARE(int(format1.textureTarget()), int(GL_TEXTURE_3D));
+ QCOMPARE(int(format1.internalTextureFormat()), int(GL_RGB16));
+
+ // operator== and operator!= for QGLFramebufferObjectFormat.
+ QGLFramebufferObjectFormat format1c;
+ QGLFramebufferObjectFormat format2c;
+
+ QCOMPARE(format1c, format2c);
+ QVERIFY(!(format1c != format2c));
+ format1c.setSamples(8);
+ QVERIFY(!(format1c == format2c));
+ QVERIFY(format1c != format2c);
+ format2c.setSamples(8);
+ QCOMPARE(format1c, format2c);
+ QVERIFY(!(format1c != format2c));
+
+ format1c.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ QVERIFY(!(format1c == format2c));
+ QVERIFY(format1c != format2c);
+ format2c.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+ QCOMPARE(format1c, format2c);
+ QVERIFY(!(format1c != format2c));
+
+ format1c.setTextureTarget(GL_TEXTURE_3D);
+ QVERIFY(!(format1c == format2c));
+ QVERIFY(format1c != format2c);
+ format2c.setTextureTarget(GL_TEXTURE_3D);
+ QCOMPARE(format1c, format2c);
+ QVERIFY(!(format1c != format2c));
+
+ format1c.setInternalTextureFormat(GL_RGB16);
+ QVERIFY(!(format1c == format2c));
+ QVERIFY(format1c != format2c);
+ format2c.setInternalTextureFormat(GL_RGB16);
+ QCOMPARE(format1c, format2c);
+ QVERIFY(!(format1c != format2c));
+
+ QGLFramebufferObjectFormat format3c(format1c);
+ QGLFramebufferObjectFormat format4c;
+ QCOMPARE(format1c, format3c);
+ QVERIFY(!(format1c != format3c));
+ format3c.setInternalTextureFormat(
+#ifdef QT_OPENGL_ES_2
+ GL_RGBA
+#else
+ QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? GL_RGBA : GL_RGBA8
+#endif
+ );
+ QVERIFY(!(format1c == format3c));
+ QVERIFY(format1c != format3c);
+
+ format4c = format1c;
+ QCOMPARE(format1c, format4c);
+ QVERIFY(!(format1c != format4c));
+ format4c.setInternalTextureFormat(
+#ifdef QT_OPENGL_ES_2
+ GL_RGBA
+#else
+ QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? GL_RGBA : GL_RGBA8
+#endif
+ );
+ QVERIFY(!(format1c == format4c));
+ QVERIFY(format1c != format4c);
+}
+
+void tst_QGL::testDontCrashOnDanglingResources()
+{
+ // We have a number of Q_GLOBAL_STATICS inside the Qt OpenGL
+ // module. This test is verify that we don't crash as a result of
+ // them calling into libgl on application shutdown.
+ QWidget *widget = new UnclippedWidget();
+ widget->show();
+ qApp->processEvents();
+ widget->hide();
+}
+
+class ReplaceClippingGLWidget : public QGLWidget
+{
+public:
+ void paint(QPainter *painter)
+ {
+ painter->fillRect(rect(), Qt::white);
+
+ QPainterPath path;
+ path.addRect(0, 0, 100, 100);
+ path.addRect(50, 50, 100, 100);
+
+ painter->setClipRect(0, 0, 150, 150);
+ painter->fillPath(path, Qt::red);
+
+ painter->translate(150, 150);
+ painter->setClipRect(0, 0, 150, 150);
+ painter->fillPath(path, Qt::red);
+ }
+
+protected:
+ void paintEvent(QPaintEvent*)
+ {
+ // clear the stencil with junk
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ funcs->glStencilMask(0xFFFF);
+ funcs->glClearStencil(0xFFFF);
+ funcs->glDisable(GL_STENCIL_TEST);
+ funcs->glDisable(GL_SCISSOR_TEST);
+ funcs->glClear(GL_STENCIL_BUFFER_BIT);
+
+ QPainter painter(this);
+ paint(&painter);
+ }
+};
+
+void tst_QGL::replaceClipping()
+{
+ ReplaceClippingGLWidget glw;
+ glw.resize(300, 300);
+ glw.show();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&glw));
+
+ QImage reference(300, 300, QImage::Format_RGB32);
+ QPainter referencePainter(&reference);
+ glw.paint(&referencePainter);
+ referencePainter.end();
+
+#if defined(Q_OS_QNX)
+ // glReadPixels reads from the back buffer. On QNX the buffer is not preserved
+ // after a buffer swap. This is why we have to swap the buffer explicitly before calling
+ // grabFrameBuffer to retrieve the content of the front buffer
+ glw.swapBuffers();
+#endif
+ const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
+
+ // Sample pixels in a grid pattern which avoids false failures due to
+ // off-by-one pixel errors on some buggy GL implementations
+ for (int x = 25; x < reference.width(); x += 50) {
+ for (int y = 25; y < reference.width(); y += 50) {
+ QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y));
+ }
+ }
+}
+
+class ClipTestGLWidget : public QGLWidget
+{
+public:
+ void paint(QPainter *painter)
+ {
+ painter->fillRect(-1, -1, width()+2, height()+2, Qt::white);
+ painter->setClipRect(10, 10, width()-20, height()-20);
+ painter->fillRect(rect(), Qt::cyan);
+
+ painter->save();
+ painter->setClipRect(10, 10, 100, 100, Qt::IntersectClip);
+
+ painter->fillRect(rect(), Qt::blue);
+
+ painter->save();
+ painter->setClipRect(10, 10, 50, 50, Qt::IntersectClip);
+ painter->fillRect(rect(), Qt::red);
+ painter->restore();
+ painter->fillRect(0, 0, 40, 40, Qt::white);
+ painter->save();
+
+ painter->setClipRect(0, 0, 35, 35, Qt::IntersectClip);
+ painter->fillRect(rect(), Qt::black);
+ painter->restore();
+
+ painter->fillRect(0, 0, 30, 30, Qt::magenta);
+
+ painter->save();
+ painter->setClipRect(60, 10, 50, 50, Qt::ReplaceClip);
+ painter->fillRect(rect(), Qt::green);
+ painter->restore();
+
+ painter->restore();
+
+ painter->translate(100, 100);
+
+ {
+ QPainterPath path;
+ path.addRect(10, 10, 100, 100);
+ path.addRect(10, 10, 10, 10);
+ painter->setClipPath(path, Qt::IntersectClip);
+ }
+
+ painter->fillRect(rect(), Qt::blue);
+
+ painter->save();
+ {
+ QPainterPath path;
+ path.addRect(10, 10, 50, 50);
+ path.addRect(10, 10, 10, 10);
+ painter->setClipPath(path, Qt::IntersectClip);
+ }
+ painter->fillRect(rect(), Qt::red);
+ painter->restore();
+ painter->fillRect(0, 0, 40, 40, Qt::white);
+ painter->save();
+
+ {
+ QPainterPath path;
+ path.addRect(0, 0, 35, 35);
+ path.addRect(10, 10, 10, 10);
+ painter->setClipPath(path, Qt::IntersectClip);
+ }
+ painter->fillRect(rect(), Qt::black);
+ painter->restore();
+
+ painter->fillRect(0, 0, 30, 30, Qt::magenta);
+
+ painter->save();
+ {
+ QPainterPath path;
+ path.addRect(60, 10, 50, 50);
+ path.addRect(10, 10, 10, 10);
+ painter->setClipPath(path, Qt::ReplaceClip);
+ }
+ painter->fillRect(rect(), Qt::green);
+ painter->restore();
+ }
+
+protected:
+ void paintEvent(QPaintEvent*)
+ {
+ QPainter painter(this);
+ paint(&painter);
+ }
+};
+
+void tst_QGL::clipTest()
+{
+ ClipTestGLWidget glw;
+ glw.resize(220, 220);
+ glw.showNormal();
+
+ QVERIFY(QTest::qWaitForWindowExposed(&glw));
+
+ QImage reference(glw.size(), QImage::Format_RGB32);
+ QPainter referencePainter(&reference);
+ glw.paint(&referencePainter);
+ referencePainter.end();
+
+#if defined(Q_OS_QNX)
+ // glReadPixels reads from the back buffer. On QNX the buffer is not preserved
+ // after a buffer swap. This is why we have to swap the buffer explicitly before calling
+ // grabFrameBuffer to retrieve the content of the front buffer
+ glw.swapBuffers();
+#endif
+ const QImage widgetFB = glw.grabFrameBuffer(false).convertToFormat(QImage::Format_RGB32);
+
+ // Sample pixels in a grid pattern which avoids false failures due to
+ // off-by-one pixel errors on some buggy GL implementations
+ for (int x = 2; x < reference.width(); x += 5) {
+ for (int y = 2; y < reference.height(); y += 5) {
+ QFUZZY_COMPARE_PIXELS(widgetFB.pixel(x, y), reference.pixel(x, y));
+ }
+ }
+}
+
+void tst_QGL::destroyFBOAfterContext()
+{
+ if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QGLFramebufferObject not supported on this platform");
+
+ QGLWidget *glw = new QGLWidget();
+ glw->makeCurrent();
+
+ // No multisample with combined depth/stencil attachment:
+ QGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+ // Don't complicate things by using NPOT:
+ QGLFramebufferObject *fbo = new QGLFramebufferObject(256, 128, fboFormat);
+
+ // The handle should be valid until the context is destroyed.
+ QVERIFY(fbo->handle() != 0);
+ QVERIFY(fbo->isValid());
+
+ delete glw;
+
+ // The handle should now be zero.
+ QVERIFY(!fbo->handle());
+ QVERIFY(!fbo->isValid());
+
+ delete fbo;
+}
+
+#ifdef QT_BUILD_INTERNAL
+
+class tst_QGLResource
+{
+public:
+ tst_QGLResource(const QGLContext * = 0) {}
+ ~tst_QGLResource() { ++deletions; }
+
+ static int deletions;
+};
+
+int tst_QGLResource::deletions = 0;
+
+#ifdef TODO
+Q_GLOBAL_STATIC(QOpenGLContextGroupResource<tst_QGLResource>, qt_shared_test)
+#endif //TODO
+#endif // QT_BUILD_INTERNAL
+
+#ifdef QT_BUILD_INTERNAL
+void tst_QGL::shareRegister()
+{
+#ifdef TODO
+ // Create a context.
+ QGLWidget *glw1 = new QGLWidget();
+ glw1->makeCurrent();
+
+ // Nothing should be sharing with glw1's context yet.
+ QVERIFY(!glw1->isSharing());
+
+ // Create a guard for the first context.
+ QOpenGLSharedResourceGuard guard(glw1->context()->contextHandle());
+ QCOMPARE(guard.id(), 0);
+ guard.setId(3);
+ QCOMPARE(guard.id(), 3);
+
+ // Request a tst_QGLResource object for the first context.
+ tst_QGLResource *res1 = qt_shared_test()->value(glw1->context()->contextHandle());
+ QVERIFY(res1);
+ QCOMPARE(qt_shared_test()->value(glw1->context()->contextHandle()), res1);
+
+ // Create another context that shares with the first.
+ QVERIFY(!glw1->isSharing());
+ QGLWidget *glw2 = new QGLWidget(0, glw1);
+ if (!glw2->isSharing()) {
+ delete glw2;
+ delete glw1;
+ QSKIP("Context sharing is not supported");
+ }
+ QVERIFY(glw1->isSharing());
+ QVERIFY(glw1->context() != glw2->context());
+
+ // Check that the first context's resource is also on the second.
+ QCOMPARE(qt_shared_test()->value(glw1->context()), res1);
+ QCOMPARE(qt_shared_test()->value(glw2->context()), res1);
+
+ // Guard should still be the same.
+ QCOMPARE(guard.context(), glw1->context());
+ QCOMPARE(guard.id(), 3);
+
+ // Check the sharing relationships.
+ QVERIFY(QGLContext::areSharing(glw1->context(), glw1->context()));
+ QVERIFY(QGLContext::areSharing(glw2->context(), glw2->context()));
+ QVERIFY(QGLContext::areSharing(glw1->context(), glw2->context()));
+ QVERIFY(QGLContext::areSharing(glw2->context(), glw1->context()));
+ QVERIFY(!QGLContext::areSharing(0, glw2->context()));
+ QVERIFY(!QGLContext::areSharing(glw1->context(), 0));
+ QVERIFY(!QGLContext::areSharing(0, 0));
+
+ // Create a third context, not sharing with the others.
+ QGLWidget *glw3 = new QGLWidget();
+ QVERIFY(!glw3->isSharing());
+
+ // Create a guard on the standalone context.
+ QGLSharedResourceGuard guard3(glw3->context());
+ guard3.setId(5);
+
+ // Request a resource to the third context.
+ tst_QGLResource *res3 = qt_shared_test()->value(glw3->context());
+ QVERIFY(res3);
+ QCOMPARE(qt_shared_test()->value(glw1->context()), res1);
+ QCOMPARE(qt_shared_test()->value(glw2->context()), res1);
+ QCOMPARE(qt_shared_test()->value(glw3->context()), res3);
+
+ // Check the sharing relationships again.
+ QVERIFY(QGLContext::areSharing(glw1->context(), glw1->context()));
+ QVERIFY(QGLContext::areSharing(glw2->context(), glw2->context()));
+ QVERIFY(QGLContext::areSharing(glw1->context(), glw2->context()));
+ QVERIFY(QGLContext::areSharing(glw2->context(), glw1->context()));
+ QVERIFY(!QGLContext::areSharing(glw1->context(), glw3->context()));
+ QVERIFY(!QGLContext::areSharing(glw2->context(), glw3->context()));
+ QVERIFY(!QGLContext::areSharing(glw3->context(), glw1->context()));
+ QVERIFY(!QGLContext::areSharing(glw3->context(), glw2->context()));
+ QVERIFY(QGLContext::areSharing(glw3->context(), glw3->context()));
+ QVERIFY(!QGLContext::areSharing(0, glw2->context()));
+ QVERIFY(!QGLContext::areSharing(glw1->context(), 0));
+ QVERIFY(!QGLContext::areSharing(0, glw3->context()));
+ QVERIFY(!QGLContext::areSharing(glw3->context(), 0));
+ QVERIFY(!QGLContext::areSharing(0, 0));
+
+ // Shared guard should still be the same.
+ QCOMPARE(guard.context(), glw1->context());
+ QCOMPARE(guard.id(), 3);
+
+ // Delete the first context.
+ delete glw1;
+
+ // The second context should no longer register as sharing.
+ QVERIFY(!glw2->isSharing());
+
+ // The first context's resource should transfer to the second context.
+ QCOMPARE(tst_QGLResource::deletions, 0);
+ QCOMPARE(qt_shared_test()->value(glw2->context()), res1);
+ QCOMPARE(qt_shared_test()->value(glw3->context()), res3);
+
+ // Shared guard should now be the second context, with the id the same.
+ QCOMPARE(guard.context(), glw2->context());
+ QCOMPARE(guard.id(), 3);
+ QCOMPARE(guard3.context(), glw3->context());
+ QCOMPARE(guard3.id(), 5);
+
+ // Clean up and check that the resources are properly deleted.
+ delete glw2;
+ QCOMPARE(tst_QGLResource::deletions, 1);
+ delete glw3;
+ QCOMPARE(tst_QGLResource::deletions, 2);
+
+ // Guards should now be null and the id zero.
+ QVERIFY(guard.context() == 0);
+ QVERIFY(guard.id() == 0);
+ QVERIFY(guard3.context() == 0);
+ QVERIFY(guard3.id() == 0);
+#endif //TODO
+}
+#endif
+
+// Tests QGLContext::bindTexture with default options
+#ifdef QT_BUILD_INTERNAL
+void tst_QGL::qglContextDefaultBindTexture()
+{
+ QGLWidget w;
+ w.makeCurrent();
+ QGLContext *ctx = const_cast<QGLContext*>(w.context());
+
+ QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32);
+ boundImage->fill(0xFFFFFFFF);
+ QPixmap *boundPixmap = new QPixmap(256, 256);
+ boundPixmap->fill(Qt::red);
+
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+
+ GLuint boundImageTextureId = ctx->bindTexture(*boundImage);
+ GLuint boundPixmapTextureId = ctx->bindTexture(*boundPixmap);
+
+ // Make sure the image & pixmap have been added to the cache:
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Make sure the image & pixmap have the is_cached flag set:
+ QVERIFY(QImagePixmapCleanupHooks::isImageCached(*boundImage));
+ QVERIFY(QImagePixmapCleanupHooks::isPixmapCached(*boundPixmap));
+
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ // Make sure the texture IDs returned are valid:
+ QCOMPARE(funcs->glIsTexture(boundImageTextureId), GLboolean(GL_TRUE));
+ QCOMPARE(funcs->glIsTexture(boundPixmapTextureId), GLboolean(GL_TRUE));
+
+ // Make sure the textures are still valid after we delete the image/pixmap:
+ // Also check that although the textures are left intact, the cache entries are removed:
+ delete boundImage;
+ boundImage = 0;
+ QCOMPARE(funcs->glIsTexture(boundImageTextureId), GLboolean(GL_TRUE));
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+ delete boundPixmap;
+ boundPixmap = 0;
+ QCOMPARE(funcs->glIsTexture(boundPixmapTextureId), GLboolean(GL_TRUE));
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ // Finally, make sure QGLContext::deleteTexture deletes the texture IDs:
+ ctx->deleteTexture(boundImageTextureId);
+ ctx->deleteTexture(boundPixmapTextureId);
+ QCOMPARE(funcs->glIsTexture(boundImageTextureId), GLboolean(GL_FALSE));
+ QCOMPARE(funcs->glIsTexture(boundPixmapTextureId), GLboolean(GL_FALSE));
+}
+#endif
+
+#ifdef QT_BUILD_INTERNAL
+void tst_QGL::textureCleanup()
+{
+ QGLWidget w;
+ w.resize(200,200);
+ w.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&w));
+ w.makeCurrent();
+
+ // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache
+ // when the pixmap cache is cleared
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QPixmap boundPixmap(":designer.png");
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Check that the texture doesn't get removed from the cache when the pixmap is cleared
+ // as it should still be in the cache:
+ boundPixmap = QPixmap();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ QPixmapCache::clear();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Test pixmaps which have been loaded via QPixmapCache are removed from the texture cache
+ // when they are explicitly removed from the pixmap cache
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QPixmap boundPixmap(128, 128);
+ QString cacheKey = QString::fromLatin1("myPixmap");
+ QPixmapCache::insert(cacheKey, boundPixmap);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Check that the texture doesn't get removed from the cache when the pixmap is cleared
+ // as it should still be in the cache:
+ boundPixmap = QPixmap();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ // Finally, we check that the texture cache entry is removed when we remove the
+ // pixmap cache entry, which should hold the last reference:
+ QPixmapCache::remove(cacheKey);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check images & pixmaps are removed from the cache when they are deleted
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QImage *boundImage = new QImage(256, 256, QImage::Format_RGB32);
+ boundImage->fill(0xFFFFFFFF);
+ QPixmap *boundPixmap = new QPixmap(256, 256);
+ boundPixmap->fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, *boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, *boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ delete boundImage;
+ boundImage = 0;
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ delete boundPixmap;
+ boundPixmap = 0;
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check images & pixmaps are removed from the cache when they are assigned to
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QImage boundImage(256, 256, QImage::Format_RGB32);
+ boundImage.fill(0xFFFFFFFF);
+ QPixmap boundPixmap(256, 256);
+ boundPixmap.fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ boundImage = QImage(64, 64, QImage::Format_RGB32);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ boundPixmap = QPixmap(64, 64);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check images & pixmaps are removed from the cache when they are modified (detached)
+ {
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ QPainter p(&w);
+
+ QImage boundImage(256, 256, QImage::Format_RGB32);
+ boundImage.fill(0xFFFFFFFF);
+ QPixmap boundPixmap(256, 256);
+ boundPixmap.fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ boundImage.fill(0x00000000);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ boundPixmap.fill(Qt::blue);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+ }
+
+ // Check that images/pixmaps aren't removed from the cache if a shallow copy has been made
+ QImage copyOfImage;
+ QPixmap copyOfPixmap;
+ int startCacheItemCount = QGLTextureCache::instance()->size();
+ {
+ QPainter p(&w);
+
+ QImage boundImage(256, 256, QImage::Format_RGB32);
+ boundImage.fill(0xFFFFFFFF);
+ QPixmap boundPixmap(256, 256);
+ boundPixmap.fill(Qt::red);
+
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+
+ p.drawImage(0, 0, boundImage);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ p.drawPixmap(0, 0, boundPixmap);
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ // Need to call end for the GL2 paint engine to release references to pixmap if using tfp
+ p.end();
+
+ copyOfImage = boundImage;
+ copyOfPixmap = boundPixmap;
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+ } // boundImage & boundPixmap would have been deleted when they went out of scope
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+2);
+
+ copyOfImage = QImage();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount+1);
+
+ copyOfPixmap = QPixmap();
+ QCOMPARE(QGLTextureCache::instance()->size(), startCacheItemCount);
+}
+#endif
+
+namespace ThreadImages {
+
+class Producer : public QObject
+{
+ Q_OBJECT
+public:
+ Producer()
+ {
+ startTimer(20);
+
+ QThread *thread = new QThread;
+ thread->start();
+
+ connect(this, SIGNAL(destroyed()), thread, SLOT(quit()));
+
+ moveToThread(thread);
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ }
+
+signals:
+ void imageReady(const QImage &image);
+
+protected:
+ void timerEvent(QTimerEvent *)
+ {
+ QImage image(256, 256, QImage::Format_RGB32);
+ QLinearGradient g(0, 0, 0, 256);
+ g.setColorAt(0, QColor(255, 180, 180));
+ g.setColorAt(1, Qt::white);
+ g.setSpread(QGradient::ReflectSpread);
+
+ QBrush brush(g);
+ brush.setTransform(QTransform::fromTranslate(0, delta));
+ delta += 10;
+
+ QPainter p(&image);
+ p.fillRect(image.rect(), brush);
+
+ if (images.size() > 10)
+ images.removeFirst();
+
+ images.append(image);
+
+ emit imageReady(image);
+ }
+
+private:
+ QList<QImage> images;
+ int delta;
+};
+
+
+class DisplayWidget : public QGLWidget
+{
+ Q_OBJECT
+public:
+ DisplayWidget(QWidget *parent) : QGLWidget(parent) {}
+ void paintEvent(QPaintEvent *)
+ {
+ QPainter p(this);
+ p.drawImage(rect(), m_image);
+ }
+
+public slots:
+ void setImage(const QImage &image)
+ {
+ m_image = image;
+ update();
+ }
+
+private:
+ QImage m_image;
+};
+
+class Widget : public QWidget
+{
+ Q_OBJECT
+public:
+ Widget()
+ : iterations(0)
+ , display(0)
+ , producer(new Producer)
+ {
+ startTimer(400);
+ connect(this, SIGNAL(destroyed()), producer, SLOT(deleteLater()));
+ }
+
+ int iterations;
+
+protected:
+ void timerEvent(QTimerEvent *)
+ {
+ ++iterations;
+
+ delete display;
+ display = new DisplayWidget(this);
+ connect(producer, SIGNAL(imageReady(QImage)), display, SLOT(setImage(QImage)));
+
+ display->setGeometry(rect());
+ display->show();
+ }
+
+private:
+ DisplayWidget *display;
+ Producer *producer;
+};
+
+}
+
+void tst_QGL::threadImages()
+{
+ ThreadImages::Widget *widget = new ThreadImages::Widget;
+ widget->show();
+
+ while (widget->iterations <= 5) {
+ qApp->processEvents();
+ }
+
+ delete widget;
+}
+
+void tst_QGL::nullRectCrash()
+{
+ if (!QGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QGLFramebufferObject not supported on this platform");
+
+ QGLWidget glw;
+ glw.makeCurrent();
+
+ QGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
+
+ QGLFramebufferObject *fbo = new QGLFramebufferObject(128, 128, fboFormat);
+
+ QPainter fboPainter(fbo);
+
+ fboPainter.setPen(QPen(QColor(255, 127, 127, 127), 2));
+ fboPainter.setBrush(QColor(127, 255, 127, 127));
+ fboPainter.drawRect(QRectF());
+
+ fboPainter.end();
+}
+
+void tst_QGL::extensions()
+{
+ QGLWidget glw;
+ glw.makeCurrent();
+
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QVERIFY(ctx);
+ QOpenGLFunctions *funcs = ctx->functions();
+ QVERIFY(funcs);
+ QSurfaceFormat format = ctx->format();
+
+#ifdef QT_BUILD_INTERNAL
+ QOpenGLExtensions *exts = static_cast<QOpenGLExtensions *>(funcs);
+ QOpenGLExtensions::OpenGLExtensions allExts = exts->openGLExtensions();
+ // Mipmapping is always available in GL2/GLES2+. Verify this.
+ if (format.majorVersion() >= 2)
+ QVERIFY(allExts.testFlag(QOpenGLExtensions::GenerateMipmap));
+#endif
+
+ // Now look for some features should always be available in a given version.
+ QOpenGLFunctions::OpenGLFeatures allFeatures = funcs->openGLFeatures();
+ QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Multitexture));
+ if (format.majorVersion() >= 2) {
+ QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Shaders));
+ QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Buffers));
+ QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Multisample));
+ QVERIFY(!ctx->isOpenGLES() || allFeatures.testFlag(QOpenGLFunctions::Framebuffers));
+ QVERIFY(allFeatures.testFlag(QOpenGLFunctions::NPOTTextures)
+ && allFeatures.testFlag(QOpenGLFunctions::NPOTTextureRepeat));
+ if (ctx->isOpenGLES()) {
+ QVERIFY(!allFeatures.testFlag(QOpenGLFunctions::FixedFunctionPipeline));
+ QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Framebuffers));
+ }
+ }
+ if (format.majorVersion() >= 3)
+ QVERIFY(allFeatures.testFlag(QOpenGLFunctions::Framebuffers));
+}
+
+QTEST_MAIN(tst_QGL)
+#include "tst_qgl.moc"
diff --git a/tests/auto/other/lancelot/paintcommands.cpp b/tests/auto/other/lancelot/paintcommands.cpp
index c1ff7e7a87..e98df3781e 100644
--- a/tests/auto/other/lancelot/paintcommands.cpp
+++ b/tests/auto/other/lancelot/paintcommands.cpp
@@ -31,6 +31,7 @@
#include <qfile.h>
#include <qfileinfo.h>
#include <qpainter.h>
+#include <qpainterpath.h>
#include <qbitmap.h>
#include <qtextstream.h>
#include <qtextlayout.h>
diff --git a/tests/auto/testlib/selftests/expected_pass.junitxml b/tests/auto/testlib/selftests/expected_pass.junitxml
new file mode 100644
index 0000000000..b148593bd0
--- /dev/null
+++ b/tests/auto/testlib/selftests/expected_pass.junitxml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<testsuite errors="0" failures="0" tests="5" name="tst_Pass">
+ <properties>
+ <property value="@INSERT_QT_VERSION_HERE@" name="QTestVersion"/>
+ <property value="@INSERT_QT_VERSION_HERE@" name="QtVersion"/>
+ <property value="" name="QtBuild"/>
+ </properties>
+ <testcase result="pass" name="initTestCase"/>
+ <testcase result="pass" name="testNumber1"/>
+ <testcase result="pass" name="testNumber2"/>
+ <testcase result="pass" name="testNumber3"/>
+ <testcase result="pass" name="cleanupTestCase"/>
+ <system-err/>
+</testsuite>
diff --git a/tests/auto/testlib/selftests/expected_pass.lightxml b/tests/auto/testlib/selftests/expected_pass.lightxml
new file mode 100644
index 0000000000..4d344e93cf
--- /dev/null
+++ b/tests/auto/testlib/selftests/expected_pass.lightxml
@@ -0,0 +1,26 @@
+<Environment>
+ <QtVersion>@INSERT_QT_VERSION_HERE@</QtVersion>
+ <QtBuild/>
+ <QTestVersion>@INSERT_QT_VERSION_HERE@</QTestVersion>
+</Environment>
+<TestFunction name="initTestCase">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="testNumber1">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="testNumber2">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="testNumber3">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="cleanupTestCase">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<Duration msecs="0"/>
diff --git a/tests/auto/testlib/selftests/expected_pass.tap b/tests/auto/testlib/selftests/expected_pass.tap
new file mode 100644
index 0000000000..a01755dc25
--- /dev/null
+++ b/tests/auto/testlib/selftests/expected_pass.tap
@@ -0,0 +1,11 @@
+TAP version 13
+# tst_Pass
+ok 1 - initTestCase()
+ok 2 - testNumber1()
+ok 3 - testNumber2()
+ok 4 - testNumber3()
+ok 5 - cleanupTestCase()
+1..5
+# tests 5
+# pass 5
+# fail 0
diff --git a/tests/auto/testlib/selftests/expected_pass.teamcity b/tests/auto/testlib/selftests/expected_pass.teamcity
new file mode 100644
index 0000000000..11dc666fb7
--- /dev/null
+++ b/tests/auto/testlib/selftests/expected_pass.teamcity
@@ -0,0 +1,12 @@
+##teamcity[testSuiteStarted name='tst_Pass' flowId='tst_Pass']
+##teamcity[testStarted name='initTestCase()' flowId='tst_Pass']
+##teamcity[testFinished name='initTestCase()' flowId='tst_Pass']
+##teamcity[testStarted name='testNumber1()' flowId='tst_Pass']
+##teamcity[testFinished name='testNumber1()' flowId='tst_Pass']
+##teamcity[testStarted name='testNumber2()' flowId='tst_Pass']
+##teamcity[testFinished name='testNumber2()' flowId='tst_Pass']
+##teamcity[testStarted name='testNumber3()' flowId='tst_Pass']
+##teamcity[testFinished name='testNumber3()' flowId='tst_Pass']
+##teamcity[testStarted name='cleanupTestCase()' flowId='tst_Pass']
+##teamcity[testFinished name='cleanupTestCase()' flowId='tst_Pass']
+##teamcity[testSuiteFinished name='tst_Pass' flowId='tst_Pass']
diff --git a/tests/auto/testlib/selftests/expected_pass.txt b/tests/auto/testlib/selftests/expected_pass.txt
new file mode 100644
index 0000000000..0d7265f970
--- /dev/null
+++ b/tests/auto/testlib/selftests/expected_pass.txt
@@ -0,0 +1,9 @@
+********* Start testing of tst_Pass *********
+Config: Using QtTest library
+PASS : tst_Pass::initTestCase()
+PASS : tst_Pass::testNumber1()
+PASS : tst_Pass::testNumber2()
+PASS : tst_Pass::testNumber3()
+PASS : tst_Pass::cleanupTestCase()
+Totals: 5 passed, 0 failed, 0 skipped, 0 blacklisted, 0ms
+********* Finished testing of tst_Pass *********
diff --git a/tests/auto/testlib/selftests/expected_pass.xml b/tests/auto/testlib/selftests/expected_pass.xml
new file mode 100644
index 0000000000..b221cb5411
--- /dev/null
+++ b/tests/auto/testlib/selftests/expected_pass.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<TestCase name="tst_Pass">
+<Environment>
+ <QtVersion>@INSERT_QT_VERSION_HERE@</QtVersion>
+ <QtBuild/>
+ <QTestVersion>@INSERT_QT_VERSION_HERE@</QTestVersion>
+</Environment>
+<TestFunction name="initTestCase">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="testNumber1">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="testNumber2">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="testNumber3">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<TestFunction name="cleanupTestCase">
+<Incident type="pass" file="" line="0" />
+ <Duration msecs="0"/>
+</TestFunction>
+<Duration msecs="0"/>
+</TestCase>
diff --git a/tests/auto/testlib/selftests/pass/pass.pro b/tests/auto/testlib/selftests/pass/pass.pro
new file mode 100644
index 0000000000..dd00a1c744
--- /dev/null
+++ b/tests/auto/testlib/selftests/pass/pass.pro
@@ -0,0 +1,9 @@
+SOURCES += tst_pass.cpp
+QT = core testlib
+
+macos:CONFIG -= app_bundle
+CONFIG -= debug_and_release_target
+
+TARGET = pass
+
+include($$QT_SOURCE_TREE/src/testlib/selfcover.pri)
diff --git a/tests/auto/testlib/selftests/pass/tst_pass.cpp b/tests/auto/testlib/selftests/pass/tst_pass.cpp
new file mode 100644
index 0000000000..6fa5f6a209
--- /dev/null
+++ b/tests/auto/testlib/selftests/pass/tst_pass.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QCoreApplication>
+#include <QtTest/QtTest>
+
+class tst_Pass: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testNumber1() const;
+ void testNumber2() const;
+ void testNumber3() const;
+};
+
+void tst_Pass::testNumber1() const
+{
+}
+
+void tst_Pass::testNumber2() const
+{
+}
+
+void tst_Pass::testNumber3() const
+{
+}
+
+QTEST_MAIN(tst_Pass)
+
+#include "tst_pass.moc"
diff --git a/tests/auto/testlib/selftests/selftests.pri b/tests/auto/testlib/selftests/selftests.pri
index 2cad0b7e17..b124b21981 100644
--- a/tests/auto/testlib/selftests/selftests.pri
+++ b/tests/auto/testlib/selftests/selftests.pri
@@ -31,6 +31,7 @@ SUBPROGRAMS = \
longstring \
maxwarnings \
multiexec \
+ pass \
pairdiagnostics \
printdatatags \
printdatatagswithglobaltags \
diff --git a/tests/auto/testlib/selftests/tst_selftests.cpp b/tests/auto/testlib/selftests/tst_selftests.cpp
index be64752ceb..cab6589984 100644
--- a/tests/auto/testlib/selftests/tst_selftests.cpp
+++ b/tests/auto/testlib/selftests/tst_selftests.cpp
@@ -422,9 +422,9 @@ void tst_Selftests::initTestCase()
{
QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString()));
//Detect the location of the sub programs
- QString subProgram = QLatin1String("float/float");
+ QString subProgram = QLatin1String("pass/pass");
#if defined(Q_OS_WIN)
- subProgram = QLatin1String("float/float.exe");
+ subProgram = QLatin1String("pass/pass.exe");
#endif
QString testdataDir = QFINDTESTDATA(subProgram);
if (testdataDir.lastIndexOf(subProgram) > 0)
@@ -487,6 +487,7 @@ void tst_Selftests::runSubTest_data()
<< "longstring"
<< "maxwarnings"
<< "multiexec"
+ << "pass"
<< "pairdiagnostics"
<< "printdatatags"
<< "printdatatagswithglobaltags"
diff --git a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp
index fe6ef5a00a..1cc793503a 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -59,6 +59,7 @@
#include <QSharedPointer>
#include <float.h>
#include <QStyleHints>
+#include <QPainterPath>
using AbstractGraphicsShapeItemPtr = QSharedPointer<QAbstractGraphicsShapeItem>;
using GraphicsItems = QVector<QGraphicsItem *>;
diff --git a/tests/auto/widgets/graphicsview/qgraphicspixmapitem/tst_qgraphicspixmapitem.cpp b/tests/auto/widgets/graphicsview/qgraphicspixmapitem/tst_qgraphicspixmapitem.cpp
index 2822279190..e7bba010d9 100644
--- a/tests/auto/widgets/graphicsview/qgraphicspixmapitem/tst_qgraphicspixmapitem.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicspixmapitem/tst_qgraphicspixmapitem.cpp
@@ -30,6 +30,7 @@
#include <QtTest/QtTest>
#include <qgraphicsscene.h>
#include <qgraphicsitem.h>
+#include <qpainterpath.h>
class tst_QGraphicsPixmapItem : public QObject
{
diff --git a/tests/auto/widgets/graphicsview/qgraphicspolygonitem/tst_qgraphicspolygonitem.cpp b/tests/auto/widgets/graphicsview/qgraphicspolygonitem/tst_qgraphicspolygonitem.cpp
index fbdd38804d..5380dd0daf 100644
--- a/tests/auto/widgets/graphicsview/qgraphicspolygonitem/tst_qgraphicspolygonitem.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicspolygonitem/tst_qgraphicspolygonitem.cpp
@@ -29,6 +29,7 @@
#include <QtTest/QtTest>
#include <qgraphicsitem.h>
+#include <qpainterpath.h>
#include <qpen.h>
diff --git a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
index cfbe1f96ee..7e5d94da22 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsscene/tst_qgraphicsscene.cpp
@@ -37,6 +37,7 @@
#include <QtWidgets/QStyleFactory>
#include <QtWidgets/QVBoxLayout>
+#include <QtGui/QPainterPath>
#include <QtGui/QScreen>
#include <QtTest/QtTest>
diff --git a/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp b/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp
index baccf7bff8..ff01810938 100644
--- a/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicssceneindex/tst_qgraphicssceneindex.cpp
@@ -28,6 +28,7 @@
#include <QtTest/QtTest>
+#include <QtGui/QPainterPath>
#include <QtWidgets/qgraphicsscene.h>
#include <private/qgraphicsscenebsptreeindex_p.h>
#include <private/qgraphicssceneindex_p.h>
diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview_2.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview_2.cpp
index bd470dbcfc..297e83421b 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview_2.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview_2.cpp
@@ -30,6 +30,7 @@
#include <QtCore/QRectF>
#include <QtGui/QTransform>
#include <QtGui/QGuiApplication>
+#include <QtGui/QPainterPath>
#include <QtGui/QScreen>
#include <QtWidgets/QStyle>
#include <QtWidgets/QStyleFactory>
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index 1f2060942b..2483d7b5bb 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -58,6 +58,7 @@
#include <qtoolbutton.h>
#include <QtCore/qoperatingsystemversion.h>
#include <QtGui/qpaintengine.h>
+#include <QtGui/qpainterpath.h>
#include <QtGui/qbackingstore.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qplatformwindow.h>
diff --git a/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp b/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp
index 485306a8ac..82804a0977 100644
--- a/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp
+++ b/tests/benchmarks/gui/painting/qpainter/tst_qpainter.cpp
@@ -28,6 +28,7 @@
#include <qtest.h>
#include <QPainter>
+#include <QPainterPath>
#include <QPixmap>
#include <QImage>
#include <QPaintEngine>
diff --git a/tests/benchmarks/gui/painting/qtbench/benchmarktests.h b/tests/benchmarks/gui/painting/qtbench/benchmarktests.h
index b31b6823aa..6d388fcaad 100644
--- a/tests/benchmarks/gui/painting/qtbench/benchmarktests.h
+++ b/tests/benchmarks/gui/painting/qtbench/benchmarktests.h
@@ -37,6 +37,7 @@
#include <QDebug>
#include <QStaticText>
#include <QPainter>
+#include <QPainterPath>
#include <QRandomGenerator>
class Benchmark
diff --git a/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp b/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp
index 12e85d4842..d28f9502d7 100644
--- a/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp
+++ b/tests/benchmarks/gui/painting/qtransform/tst_qtransform.cpp
@@ -28,6 +28,7 @@
#include <qtest.h>
#include <QTransform>
+#include <QPainterPath>
class tst_QTransform : public QObject
{