summaryrefslogtreecommitdiffstats
path: root/tests/auto/gui
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/gui')
-rw-r--r--tests/auto/gui/image/CMakeLists.txt4
-rw-r--r--tests/auto/gui/image/qicoimageformat/qicoimageformat.qrc18
-rw-r--r--tests/auto/gui/image/qicon/tst_qicon.qrc31
-rw-r--r--tests/auto/gui/image/qimage/qimage.qrc22
-rw-r--r--tests/auto/gui/image/qimagereader/tst_qimagereader.cpp8
-rw-r--r--tests/auto/gui/image/qimagewriter/qimagewriter.qrc16
-rw-r--r--tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp2
-rw-r--r--tests/auto/gui/image/qmovie/tst_qmovie.cpp1
-rw-r--r--tests/auto/gui/image/qpixmap/qpixmap.qrc51
-rw-r--r--tests/auto/gui/image/qpixmap/tst_qpixmap.cpp2
-rw-r--r--tests/auto/gui/kernel/CMakeLists.txt7
-rw-r--r--tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp206
-rw-r--r--tests/auto/gui/kernel/qguiapplication/BLACKLIST3
-rw-r--r--tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp116
-rw-r--r--tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.qrc6
-rw-r--r--tests/auto/gui/kernel/qguivariant/test/qguivariant.qrc5
-rw-r--r--tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp19
-rw-r--r--tests/auto/gui/kernel/qkeysequence/qkeysequence.qrc6
-rw-r--r--tests/auto/gui/kernel/qpalette/tst_qpalette.cpp8
-rw-r--r--tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp198
-rw-r--r--tests/auto/gui/kernel/qwindow/tst_qwindow.cpp44
-rw-r--r--tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp29
-rw-r--r--tests/auto/gui/painting/qpainter/testdata.qrc186
-rw-r--r--tests/auto/gui/painting/qpainter/tst_qpainter.cpp45
-rw-r--r--tests/auto/gui/rhi/qrhi/BLACKLIST10
-rw-r--r--tests/auto/gui/rhi/qrhi/data/buildshaders.bat1
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag14
-rw-r--r--tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag.qsbbin0 -> 1258 bytes
-rw-r--r--tests/auto/gui/rhi/qrhi/qrhi.qrc5
-rw-r--r--tests/auto/gui/rhi/qrhi/tst_qrhi.cpp885
-rw-r--r--tests/auto/gui/rhi/qshader/data/texture_sep.frag17
-rw-r--r--tests/auto/gui/rhi/qshader/data/texture_sep_v6.frag.qsbbin0 -> 1265 bytes
-rw-r--r--tests/auto/gui/rhi/qshader/qshader.qrc5
-rw-r--r--tests/auto/gui/rhi/qshader/tst_qshader.cpp46
-rw-r--r--tests/auto/gui/text/qcssparser/testdata.qrc18
-rw-r--r--tests/auto/gui/text/qcssparser/tst_qcssparser.cpp30
-rw-r--r--tests/auto/gui/text/qfont/CMakeLists.txt1
-rw-r--r--tests/auto/gui/text/qfont/datastream.515bin0 -> 121 bytes
-rw-r--r--tests/auto/gui/text/qfont/testfont.qrc5
-rw-r--r--tests/auto/gui/text/qfont/tst_qfont.cpp38
-rw-r--r--tests/auto/gui/text/qfontdatabase/testdata.qrc9
-rw-r--r--tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp39
-rw-r--r--tests/auto/gui/text/qfontmetrics/testfont.qrc6
-rw-r--r--tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp37
-rw-r--r--tests/auto/gui/text/qglyphrun/testdata.qrc5
-rw-r--r--tests/auto/gui/text/qrawfont/testdata.qrc7
-rw-r--r--tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp139
-rw-r--r--tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp9
-rw-r--r--tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp112
-rw-r--r--tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp36
-rw-r--r--tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp35
-rw-r--r--tests/auto/gui/text/qtexttable/tst_qtexttable.cpp89
-rw-r--r--tests/auto/gui/text/qzip/testdata.qrc6
-rw-r--r--tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc11
54 files changed, 1976 insertions, 672 deletions
diff --git a/tests/auto/gui/image/CMakeLists.txt b/tests/auto/gui/image/CMakeLists.txt
index 14930536c9..27916d0409 100644
--- a/tests/auto/gui/image/CMakeLists.txt
+++ b/tests/auto/gui/image/CMakeLists.txt
@@ -4,7 +4,9 @@
if(TARGET Qt::Network AND NOT ANDROID)
add_subdirectory(qimagereader)
endif()
-add_subdirectory(qicoimageformat)
+if(QT_FEATURE_ico)
+ add_subdirectory(qicoimageformat)
+endif()
add_subdirectory(qpixmap)
add_subdirectory(qimage)
add_subdirectory(qimageiohandler)
diff --git a/tests/auto/gui/image/qicoimageformat/qicoimageformat.qrc b/tests/auto/gui/image/qicoimageformat/qicoimageformat.qrc
deleted file mode 100644
index 1e0ee8aa8c..0000000000
--- a/tests/auto/gui/image/qicoimageformat/qicoimageformat.qrc
+++ /dev/null
@@ -1,18 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>icons/invalid/35floppy.ico</file>
- <file>icons/valid/35FLOPPY.ICO</file>
- <file>icons/valid/abcardWindow.ico</file>
- <file>icons/valid/AddPerfMon.ico</file>
- <file>icons/valid/App.ico</file>
- <file>icons/valid/Obj_N2_Internal_Mem.ico</file>
- <file>icons/valid/Qt.ico</file>
- <file>icons/valid/semitransparent.ico</file>
- <file>icons/valid/Status_Play.ico</file>
- <file>icons/valid/TIMER01.ICO</file>
- <file>icons/valid/trolltechlogo_tiny.ico</file>
- <file>icons/valid/WORLD.ico</file>
- <file>icons/valid/WORLDH.ico</file>
- <file>icons/valid/yellow.cur</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/image/qicon/tst_qicon.qrc b/tests/auto/gui/image/qicon/tst_qicon.qrc
deleted file mode 100644
index 23a6801e38..0000000000
--- a/tests/auto/gui/image/qicon/tst_qicon.qrc
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource prefix="/">
-<file>tst_qicon.cpp</file>
-<file>image.png</file>
-<file>rect.png</file>
-<file>./icons/testtheme/16x16/actions/appointment-new.png</file>
-<file>./icons/testtheme/22x22/actions/appointment-new.png</file>
-<file>./second_icons/testtheme/32x32/actions/appointment-new.png</file>
-<file>./fallback_icons/red.png</file>
-<file>./icons/testtheme/index.theme</file>
-<file>./icons/testtheme/scalable/actions/svg-only.svg</file>
-<file>./icons/themeparent/16x16/actions/address-book-new.png</file>
-<file>./icons/themeparent/16x16/actions/appointment-new.png</file>
-<file>./icons/themeparent/22x22/actions/address-book-new.png</file>
-<file>./icons/themeparent/22x22/actions/appointment-new.png</file>
-<file>./icons/themeparent/32x32/actions/address-book-new.png</file>
-<file>./icons/themeparent/32x32/actions/appointment-new.png</file>
-<file>./icons/themeparent/index.theme</file>
-<file>./icons/themeparent/icon-theme.cache</file>
-<file>./icons/themeparent/scalable/actions/address-book-new.svg</file>
-<file>./icons/themeparent/scalable/actions/appointment-new.svg</file>
-<file>./styles/commonstyle/images/standardbutton-open-16.png</file>
-<file>./styles/commonstyle/images/standardbutton-open-32.png</file>
-<file>./styles/commonstyle/images/standardbutton-open-64.png</file>
-<file>./styles/commonstyle/images/standardbutton-open-128.png</file>
-<file>./styles/commonstyle/images/standardbutton-save-16.png</file>
-<file>./styles/commonstyle/images/standardbutton-save-32.png</file>
-<file>./styles/commonstyle/images/standardbutton-save-64.png</file>
-<file>./styles/commonstyle/images/standardbutton-save-128.png</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/gui/image/qimage/qimage.qrc b/tests/auto/gui/image/qimage/qimage.qrc
deleted file mode 100644
index e5de27faf8..0000000000
--- a/tests/auto/gui/image/qimage/qimage.qrc
+++ /dev/null
@@ -1,22 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>images/image.bmp</file>
- <file>images/image.gif</file>
- <file>images/image.ico</file>
- <file>images/image.jpg</file>
- <file>images/image.pbm</file>
- <file>images/image.pgm</file>
- <file>images/image.png</file>
- <file>images/image.ppm</file>
- <file>images/image.xbm</file>
- <file>images/image.xpm</file>
- <file>images/jpeg_exif_orientation_value_1.jpg</file>
- <file>images/jpeg_exif_orientation_value_2.jpg</file>
- <file>images/jpeg_exif_orientation_value_3.jpg</file>
- <file>images/jpeg_exif_orientation_value_4.jpg</file>
- <file>images/jpeg_exif_orientation_value_5.jpg</file>
- <file>images/jpeg_exif_orientation_value_6.jpg</file>
- <file>images/jpeg_exif_orientation_value_7.jpg</file>
- <file>images/jpeg_exif_orientation_value_8.jpg</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp
index 1019def466..3191f9f06b 100644
--- a/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp
+++ b/tests/auto/gui/image/qimagereader/tst_qimagereader.cpp
@@ -1953,6 +1953,10 @@ void tst_QImageReader::readText_data()
void tst_QImageReader::readText()
{
+#ifdef QT_NO_IMAGEIO_TEXT_LOADING
+ QSKIP("Reading text from image is configured away");
+#endif
+
QFETCH(QString, fileName);
QFETCH(QString, key);
QFETCH(QString, text);
@@ -1994,6 +1998,10 @@ void tst_QImageReader::preserveTexts_data()
void tst_QImageReader::preserveTexts()
{
+#ifdef QT_NO_IMAGEIO_TEXT_LOADING
+ QSKIP("Reading text from image is configured away");
+#endif
+
QFETCH(QString, fileName);
QByteArray format = fileName.right(3).toLatin1();
QFETCH(QString, text);
diff --git a/tests/auto/gui/image/qimagewriter/qimagewriter.qrc b/tests/auto/gui/image/qimagewriter/qimagewriter.qrc
deleted file mode 100644
index 29b036e303..0000000000
--- a/tests/auto/gui/image/qimagewriter/qimagewriter.qrc
+++ /dev/null
@@ -1,16 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>images/beavis.jpg</file>
- <file>images/colorful.bmp</file>
- <file>images/earth.gif</file>
- <file>images/font.bmp</file>
- <file>images/gnus.xbm</file>
- <file>images/kollada.png</file>
- <file>images/marble.xpm</file>
- <file>images/ship63.pbm</file>
- <file>images/teapot.ppm</file>
- <file>images/trolltech.gif</file>
- <file>images/YCbCr_cmyk.jpg</file>
- <file>images/YCbCr_rgb.jpg</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp b/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp
index 6ce8060306..2f3c744fd9 100644
--- a/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp
+++ b/tests/auto/gui/image/qimagewriter/tst_qimagewriter.cpp
@@ -281,6 +281,8 @@ void tst_QImageWriter::writeImage2()
QFETCH(QByteArray, format);
QFETCH(QImage, image);
+ SKIP_IF_UNSUPPORTED(format);
+
//we reduce the scope of writer so that it closes the associated file
// and QFile::remove can actually work
{
diff --git a/tests/auto/gui/image/qmovie/tst_qmovie.cpp b/tests/auto/gui/image/qmovie/tst_qmovie.cpp
index c1abeccba5..11592ffc2a 100644
--- a/tests/auto/gui/image/qmovie/tst_qmovie.cpp
+++ b/tests/auto/gui/image/qmovie/tst_qmovie.cpp
@@ -36,6 +36,7 @@
#include <QLabel>
#endif
#include <QMovie>
+#include <QProperty>
class tst_QMovie : public QObject
{
diff --git a/tests/auto/gui/image/qpixmap/qpixmap.qrc b/tests/auto/gui/image/qpixmap/qpixmap.qrc
deleted file mode 100644
index 3965622dba..0000000000
--- a/tests/auto/gui/image/qpixmap/qpixmap.qrc
+++ /dev/null
@@ -1,51 +0,0 @@
-<RCC>
- <qresource>
- <file>loadFromData/designer_argb32.png</file>
- <file>loadFromData/designer_indexed8_no_alpha_animated.gif</file>
- <file>loadFromData/designer_indexed8_no_alpha.gif</file>
- <file>loadFromData/designer_indexed8_no_alpha.png</file>
- <file>loadFromData/designer_indexed8_with_alpha_animated.gif</file>
- <file>loadFromData/designer_indexed8_with_alpha.gif</file>
- <file>loadFromData/designer_indexed8_with_alpha.png</file>
- <file>loadFromData/designer_rgb32.jpg</file>
- <file>loadFromData/designer_rgb32.png</file>
- <file>convertFromImage/task31722_1/img1.png</file>
- <file>convertFromImage/task31722_1/img2.png</file>
- <file>convertFromToHICON/icon_8bpp_16x16.png</file>
- <file>convertFromToHICON/icon_8bpp_32x32.png</file>
- <file>convertFromToHICON/icon_8bpp_48x48.png</file>
- <file>convertFromToHICON/icon_8bpp.ico</file>
- <file>convertFromToHICON/icon_32bpp_16x16.png</file>
- <file>convertFromToHICON/icon_32bpp_32x32.png</file>
- <file>convertFromToHICON/icon_32bpp_48x48.png</file>
- <file>convertFromToHICON/icon_32bpp_256x256.png</file>
- <file>convertFromToHICON/icon_32bpp.ico</file>
- <file>convertFromImage/task31722_0/img1.png</file>
- <file>convertFromImage/task31722_0/img2.png</file>
- <file>images/designer.png</file>
- <file>images/dx_0_dy_0_50_50_100_100.png</file>
- <file>images/dx_0_dy_0_null.png</file>
- <file>images/dx_0_dy_0_x_y_w_h.png</file>
- <file>images/dx_0_dy_-10_50_50_100_100.png</file>
- <file>images/dx_0_dy_10_50_50_100_100.png</file>
- <file>images/dx_0_dy_-10_x_y_w_h.png</file>
- <file>images/dx_0_dy_10_x_y_w_h.png</file>
- <file>images/dx_0_dy_-128_x_y_w_h.png</file>
- <file>images/dx_0_dy_128_x_y_w_h.png</file>
- <file>images/dx_0_dy_1_null.png</file>
- <file>images/dx_-10_dy_0_50_50_100_100.png</file>
- <file>images/dx_10_dy_0_50_50_100_100.png</file>
- <file>images/dx_-10_dy_0_x_y_w_h.png</file>
- <file>images/dx_10_dy_0_x_y_w_h.png</file>
- <file>images/dx_-10_dy_-10_50_50_100_100.png</file>
- <file>images/dx_10_dy_10_50_50_100_100.png</file>
- <file>images/dx_-10_dy_-10_x_y_w_h.png</file>
- <file>images/dx_10_dy_10_x_y_w_h.png</file>
- <file>images/dx_-128_dy_0_x_y_w_h.png</file>
- <file>images/dx_128_dy_0_x_y_w_h.png</file>
- <file>images/dx_128_dy_128_64_64_128_128.png</file>
- <file>images/dx_-128_dy_-128_x_y_w_h.png</file>
- <file>images/dx_128_dy_128_x_y_w_h.png</file>
- <file>images/dx_1_dy_0_null.png</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp
index 6c6c282af4..69f6796bbb 100644
--- a/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp
+++ b/tests/auto/gui/image/qpixmap/tst_qpixmap.cpp
@@ -46,7 +46,7 @@
#include <private/qdrawhelper_p.h>
#ifdef Q_OS_WIN
-#include <windows.h>
+#include <qt_windows.h>
#endif
diff --git a/tests/auto/gui/kernel/CMakeLists.txt b/tests/auto/gui/kernel/CMakeLists.txt
index 7ff4e40280..74657ed1b6 100644
--- a/tests/auto/gui/kernel/CMakeLists.txt
+++ b/tests/auto/gui/kernel/CMakeLists.txt
@@ -43,12 +43,7 @@ if(TARGET Qt::Widgets)
add_subdirectory(qtouchevent)
endif()
if(QT_FEATURE_opengl)
- # special case begin
- # QTBUG-85364
- if(NOT LINUX)
- add_subdirectory(qopenglwindow)
- endif()
- # special case end
+ add_subdirectory(qopenglwindow)
endif()
if(TARGET Qt::Network AND WIN32)
add_subdirectory(noqteventloop)
diff --git a/tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp b/tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp
index 5349119b6d..afc40bff50 100644
--- a/tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp
+++ b/tests/auto/gui/kernel/qbackingstore/tst_qbackingstore.cpp
@@ -28,6 +28,7 @@
#include <qwindow.h>
#include <qbackingstore.h>
+#include <qpa/qplatformbackingstore.h>
#include <qpainter.h>
#include <QTest>
@@ -42,9 +43,214 @@ class tst_QBackingStore : public QObject
Q_OBJECT
private slots:
+
+ void initTestCase_data();
+ void init();
+
+ void resize();
+ void paint();
+
+ void scrollRectInImage_data();
+ void scrollRectInImage();
+
+ void scroll();
void flush();
};
+void tst_QBackingStore::initTestCase_data()
+{
+ QTest::addColumn<QSurfaceFormat::SwapBehavior>("swapBehavior");
+
+ QTest::newRow("single-buffer") << QSurfaceFormat::SingleBuffer;
+ QTest::newRow("double-buffer") << QSurfaceFormat::DoubleBuffer;
+}
+
+void tst_QBackingStore::init()
+{
+ QFETCH_GLOBAL(QSurfaceFormat::SwapBehavior, swapBehavior);
+
+ QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat();
+ defaultFormat.setSwapBehavior(swapBehavior);
+ QSurfaceFormat::setDefaultFormat(defaultFormat);
+}
+
+void tst_QBackingStore::resize()
+{
+ QWindow window;
+ window.create();
+
+ QBackingStore backingStore(&window);
+
+ QRect rect(0, 0, 100, 100);
+ backingStore.resize(rect.size());
+ QCOMPARE(backingStore.size(), rect.size());
+
+ // The paint device should reflect the requested
+ // size, taking the window's DPR into account.
+ backingStore.beginPaint(rect);
+ auto paintDevice = backingStore.paintDevice();
+ QCOMPARE(paintDevice->devicePixelRatio(), window.devicePixelRatio());
+ QCOMPARE(QSize(paintDevice->width(), paintDevice->height()),
+ rect.size() * window.devicePixelRatio());
+ backingStore.endPaint();
+
+ // So should the platform backingstore when accessed as an QImage
+ QImage image = backingStore.handle()->toImage();
+ if (!image.isNull()) // toImage might not be implemented
+ QCOMPARE(image.size(), rect.size() * window.devicePixelRatio());
+}
+
+void tst_QBackingStore::paint()
+{
+ QWindow window;
+ window.create();
+
+ // The resize() test verifies that the backingstore image
+ // has a size that takes the window's DPR into account.
+ auto dpr = window.devicePixelRatio();
+
+ QBackingStore backingStore(&window);
+
+ QRect rect(0, 0, 100, 100);
+ backingStore.resize(rect.size());
+
+ // Two rounds, with flush in between
+ for (int i = 0; i < 2; ++i) {
+ backingStore.beginPaint(rect);
+ QPainter p(backingStore.paintDevice());
+ QColor bgColor = i ? Qt::red : Qt::blue;
+ QColor fgColor = i ? Qt::green : Qt::yellow;
+ p.fillRect(rect, bgColor);
+ p.fillRect(QRect(50, 50, 10, 10), fgColor);
+ p.end();
+ backingStore.endPaint();
+
+ QImage image = backingStore.handle()->toImage();
+ if (image.isNull())
+ QSKIP("Platform backingstore does not implement toImage");
+
+ QCOMPARE(image.pixelColor(50 * dpr, 50 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(49 * dpr, 50 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(50 * dpr, 49 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(59 * dpr, 59 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(60 * dpr, 59 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(59 * dpr, 60 * dpr), bgColor);
+
+ backingStore.flush(rect);
+ }
+}
+
+void tst_QBackingStore::scrollRectInImage_data()
+{
+ QTest::addColumn<QRect>("rect");
+ QTest::addColumn<QPoint>("offset");
+
+ QTest::newRow("empty rect") << QRect() << QPoint();
+ QTest::newRow("rect outside image") << QRect(-100, -100, 1000, 1000) << QPoint(10, 10);
+ QTest::newRow("scroll outside positive") << QRect(10, 10, 10, 10) << QPoint(1000, 1000);
+ QTest::newRow("scroll outside negative") << QRect(10, 10, 10, 10) << QPoint(-1000, -1000);
+
+ QTest::newRow("sub-rect positive scroll") << QRect(100, 100, 50, 50) << QPoint(10, 10);
+ QTest::newRow("sub-rect negative scroll") << QRect(100, 100, 50, 50) << QPoint(-10, -10);
+
+ QTest::newRow("positive vertical only") << QRect(100, 100, 50, 50) << QPoint(0, 10);
+ QTest::newRow("negative vertical only") << QRect(100, 100, 50, 50) << QPoint(0, -10);
+ QTest::newRow("positive horizontal only") << QRect(100, 100, 50, 50) << QPoint(10, 0);
+ QTest::newRow("negative horizontal only") << QRect(100, 100, 50, 50) << QPoint(-10, 0);
+
+ QTest::newRow("whole rect positive") << QRect(0, 0, 250, 250) << QPoint(10, 10);
+ QTest::newRow("whole rect negative") << QRect(0, 0, 250, 250) << QPoint(-10, -10);
+}
+
+QT_BEGIN_NAMESPACE
+Q_GUI_EXPORT void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &);
+QT_END_NAMESPACE
+
+void tst_QBackingStore::scrollRectInImage()
+{
+ QImage test(250, 250, QImage::Format_ARGB32_Premultiplied);
+
+ QFETCH(QRect, rect);
+ QFETCH(QPoint, offset);
+
+ qt_scrollRectInImage(test, rect, offset);
+}
+
+void tst_QBackingStore::scroll()
+{
+ QWindow window;
+ window.create();
+
+ // The resize() test verifies that the backingstore image
+ // has a size that takes the window's DPR into account.
+ auto dpr = window.devicePixelRatio();
+
+ QBackingStore backingStore(&window);
+ QRect rect(0, 0, 100, 100);
+
+ // Scrolling a backingstore without a size shouldn't crash
+ backingStore.scroll(rect, 10, 10);
+ backingStore.scroll(rect, -10, -10);
+
+ backingStore.resize(rect.size());
+
+ // Scrolling a backingstore without painting to it shouldn't crash
+ backingStore.scroll(rect, 10, 10);
+ backingStore.scroll(rect, -10, -10);
+
+ // Two rounds, with flush in between
+ for (int i = 0; i < 2; ++i) {
+
+ backingStore.beginPaint(rect);
+ QPainter p(backingStore.paintDevice());
+ QColor bgColor = i ? Qt::red : Qt::blue;
+ QColor fgColor = i ? Qt::green : Qt::yellow;
+ p.fillRect(rect, bgColor);
+ p.fillRect(QRect(50, 50, 10, 10), fgColor);
+ p.end();
+ backingStore.endPaint();
+
+ QImage image = backingStore.handle()->toImage();
+ if (image.isNull())
+ QSKIP("Platform backingstore does not implement toImage");
+
+ QCOMPARE(image.pixelColor(50 * dpr, 50 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(49 * dpr, 50 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(50 * dpr, 49 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(59 * dpr, 59 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(60 * dpr, 59 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(59 * dpr, 60 * dpr), bgColor);
+ image = {};
+
+ bool supportsScroll = backingStore.scroll(QRect(52, 52, 6, 6), -12, -12);
+ if (!supportsScroll)
+ QSKIP("Platform backingstore does not support scrolling");
+
+ image = backingStore.handle()->toImage();
+ QCOMPARE(image.pixelColor(40 * dpr, 40 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(39 * dpr, 40 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(40 * dpr, 39 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(45 * dpr, 45 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(46 * dpr, 45 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(45 * dpr, 46 * dpr), bgColor);
+ image = {};
+
+ backingStore.flush(rect);
+
+ // Scroll again after flush, but before new round of painting
+ backingStore.scroll(QRect(52, 52, 6, 6), 12, 12);
+
+ image = backingStore.handle()->toImage();
+ QCOMPARE(image.pixelColor(64 * dpr, 64 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(63 * dpr, 64 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(64 * dpr, 63 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(69 * dpr, 69 * dpr), fgColor);
+ QCOMPARE(image.pixelColor(70 * dpr, 69 * dpr), bgColor);
+ QCOMPARE(image.pixelColor(69 * dpr, 70 * dpr), bgColor);
+ image = {};
+ }
+}
+
class Window : public QWindow
{
public:
diff --git a/tests/auto/gui/kernel/qguiapplication/BLACKLIST b/tests/auto/gui/kernel/qguiapplication/BLACKLIST
index e6ffe78ae3..2f1e5f333e 100644
--- a/tests/auto/gui/kernel/qguiapplication/BLACKLIST
+++ b/tests/auto/gui/kernel/qguiapplication/BLACKLIST
@@ -1,3 +1,6 @@
[focusObject]
ubuntu-16.04
opensuse-42.3
+
+[quitOnLastWindowClosedWithEventLoopLocker]
+b2qt
diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp
index ec7f7dc0dc..836419659b 100644
--- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp
+++ b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.cpp
@@ -77,6 +77,7 @@ private slots:
void quitOnLastWindowClosed();
void quitOnLastWindowClosedMulti();
void dontQuitOnLastWindowClosed();
+ void quitOnLastWindowClosedWithEventLoopLocker();
void genericPluginsAndWindowSystemEvents();
void layoutDirection();
void globalShareContext();
@@ -969,6 +970,121 @@ void tst_QGuiApplication::dontQuitOnLastWindowClosed()
QCOMPARE(spyLastWindowClosed.count(), 1); // lastWindowClosed emitted
}
+class QuitSpy : public QObject
+{
+ Q_OBJECT
+public:
+ QuitSpy()
+ {
+ qGuiApp->installEventFilter(this);
+ }
+ bool eventFilter(QObject *o, QEvent *e) override
+ {
+ Q_UNUSED(o);
+ if (e->type() == QEvent::Quit)
+ ++quits;
+
+ return false;
+ }
+
+ int quits = 0;
+};
+
+void tst_QGuiApplication::quitOnLastWindowClosedWithEventLoopLocker()
+{
+ int argc = 0;
+ QGuiApplication app(argc, nullptr);
+
+ QVERIFY(app.quitOnLastWindowClosed());
+ QVERIFY(app.isQuitLockEnabled());
+
+ auto defaultRestorer = qScopeGuard([&]{
+ app.setQuitLockEnabled(true);
+ app.setQuitOnLastWindowClosed(true);
+ });
+
+ {
+ // Disabling QEventLoopLocker support should not affect
+ // quitting when last window is closed.
+ app.setQuitLockEnabled(false);
+
+ QuitSpy quitSpy;
+ QWindow window;
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QTimer::singleShot(0, &window, &QWindow::close);
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 1);
+ }
+
+ {
+ // Disabling quitOnLastWindowClosed support should not affect
+ // quitting when last QEventLoopLocker goes out of scope.
+ app.setQuitLockEnabled(true);
+ app.setQuitOnLastWindowClosed(false);
+
+ QuitSpy quitSpy;
+ QScopedPointer<QEventLoopLocker> locker(new QEventLoopLocker);
+ QWindow window;
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QTimer::singleShot(0, [&]{ locker.reset(nullptr); });
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 1);
+ }
+
+ {
+ // With both properties enabled we need to get rid of both
+ // the window and locker to trigger a quit.
+ app.setQuitLockEnabled(true);
+ app.setQuitOnLastWindowClosed(true);
+
+ QuitSpy quitSpy;
+ QScopedPointer<QEventLoopLocker> locker(new QEventLoopLocker);
+ QWindow window;
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QTimer::singleShot(0, &window, &QWindow::close);
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 0);
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QTimer::singleShot(0, [&]{ locker.reset(nullptr); });
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 0);
+
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QTimer::singleShot(0, [&]{ locker.reset(nullptr); });
+ QTimer::singleShot(0, &window, &QWindow::close);
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 1);
+ }
+
+ {
+ // With neither properties enabled we don't get automatic quit.
+ app.setQuitLockEnabled(false);
+ app.setQuitOnLastWindowClosed(false);
+
+ QuitSpy quitSpy;
+ QScopedPointer<QEventLoopLocker> locker(new QEventLoopLocker);
+ QWindow window;
+ window.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&window));
+ QTimer::singleShot(0, [&]{ locker.reset(nullptr); });
+ QTimer::singleShot(0, &window, &QWindow::close);
+ QTimer::singleShot(200, &app, []{ QCoreApplication::exit(0); });
+ app.exec();
+ QCOMPARE(quitSpy.quits, 0);
+ }
+}
+
static Qt::ScreenOrientation testOrientationToSend = Qt::PrimaryOrientation;
class TestPlugin : public QObject
diff --git a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.qrc b/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.qrc
deleted file mode 100644
index b26fba37b9..0000000000
--- a/tests/auto/gui/kernel/qguiapplication/tst_qguiapplication.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource prefix="/">
- <file>icons/usericon.png</file>
- <file>icons/appicon.png</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/gui/kernel/qguivariant/test/qguivariant.qrc b/tests/auto/gui/kernel/qguivariant/test/qguivariant.qrc
deleted file mode 100644
index 576d9cda1c..0000000000
--- a/tests/auto/gui/kernel/qguivariant/test/qguivariant.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE RCC><RCC version="1.0">
-<qresource>
- <file>data</file>
-</qresource>
-</RCC>
diff --git a/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp b/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp
index b732954230..cd721f249b 100644
--- a/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp
+++ b/tests/auto/gui/kernel/qhighdpi/tst_qhighdpi.cpp
@@ -76,6 +76,8 @@ private slots:
void mouseEvents();
void mouseVelocity();
void mouseVelocity_data();
+ void setCursor();
+ void setCursor_data();
};
/// Offscreen platform plugin test setup
@@ -805,5 +807,22 @@ void tst_QHighDpi::mouseVelocity()
}
}
+void tst_QHighDpi::setCursor_data()
+{
+ standardScreenDpiTestData();
+}
+
+void tst_QHighDpi::setCursor()
+{
+ QFETCH(QList<qreal>, dpiValues);
+ std::unique_ptr<QGuiApplication> app(createStandardOffscreenApp(dpiValues));
+
+ for (QScreen *screen : app->screens()) {
+ QPoint center = screen->geometry().center();
+ QCursor::setPos(center.x(), center.y());
+ QCOMPARE(QCursor::pos(), center);
+ }
+}
+
#include "tst_qhighdpi.moc"
QTEST_APPLESS_MAIN(tst_QHighDpi);
diff --git a/tests/auto/gui/kernel/qkeysequence/qkeysequence.qrc b/tests/auto/gui/kernel/qkeysequence/qkeysequence.qrc
deleted file mode 100644
index e224faaddd..0000000000
--- a/tests/auto/gui/kernel/qkeysequence/qkeysequence.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource>
- <file>keys_de.qm</file>
- <file>qt_de.qm</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp
index 6524f73143..9ef313f36d 100644
--- a/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp
+++ b/tests/auto/gui/kernel/qpalette/tst_qpalette.cpp
@@ -227,6 +227,14 @@ void tst_QPalette::isBrushSet()
QVERIFY(p.isBrushSet(QPalette::Active, QPalette::LinkVisited));
QVERIFY(p.isBrushSet(QPalette::Inactive, QPalette::LinkVisited));
QVERIFY(p.isBrushSet(QPalette::Disabled, QPalette::LinkVisited));
+
+ // Don't set flag when brush doesn't change (and also don't detach - QTBUG-98762)
+ QPalette p2;
+ QPalette p3;
+ QVERIFY(!p2.isBrushSet(QPalette::Active, QPalette::Dark));
+ p2.setBrush(QPalette::Active, QPalette::Dark, p2.brush(QPalette::Active, QPalette::Dark));
+ QVERIFY(!p3.isBrushSet(QPalette::Active, QPalette::Dark));
+ QVERIFY(!p2.isBrushSet(QPalette::Active, QPalette::Dark));
}
void tst_QPalette::setAllPossibleBrushes()
diff --git a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp
index 28c33e8226..cc86e866f6 100644
--- a/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp
+++ b/tests/auto/gui/kernel/qtouchevent/tst_qtouchevent.cpp
@@ -26,6 +26,7 @@
**
****************************************************************************/
+#include <QtGui/QCursor>
#include <QtGui/QScreen>
#include <QtWidgets/QGraphicsItem>
#include <QtWidgets/QGraphicsScene>
@@ -36,6 +37,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qwindowsysteminterface_p.h>
#include <private/qevent_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <private/qhighdpiscaling_p.h>
#include <private/qpointingdevice_p.h>
@@ -402,11 +404,11 @@ void tst_QTouchEvent::touchDisabledByDefault()
QVERIFY(!item.acceptTouchEvents());
// compose an event to the scene that is over the item
- QMutableEventPoint touchPoint(0);
- touchPoint.setState(QEventPoint::State::Pressed);
- touchPoint.setPosition(view.mapFromScene(item.mapToScene(item.boundingRect().center())));
- touchPoint.setGlobalPosition(view.mapToGlobal(touchPoint.position().toPoint()));
- touchPoint.setScenePosition(view.mapToScene(touchPoint.position().toPoint()));
+ QEventPoint touchPoint(0);
+ QMutableEventPoint::setState(touchPoint, QEventPoint::State::Pressed);
+ QMutableEventPoint::setPosition(touchPoint, view.mapFromScene(item.mapToScene(item.boundingRect().center())));
+ QMutableEventPoint::setGlobalPosition(touchPoint, view.mapToGlobal(touchPoint.position().toPoint()));
+ QMutableEventPoint::setScenePosition(touchPoint, view.mapToScene(touchPoint.position().toPoint()));
QTouchEvent touchEvent(QEvent::TouchBegin,
touchScreenDevice,
@@ -462,10 +464,10 @@ void tst_QTouchEvent::touchEventAcceptedByDefault()
// compose an event to the scene that is over the item
QPointF pos = view.mapFromScene(item.mapToScene(item.boundingRect().center()));
- QMutableEventPoint touchPoint(0, QEventPoint::State::Pressed,
- view.mapToScene(pos.toPoint()),
- view.mapToGlobal(pos.toPoint()));
- touchPoint.setPosition(pos);
+ QEventPoint touchPoint(0, QEventPoint::State::Pressed,
+ view.mapToScene(pos.toPoint()),
+ view.mapToGlobal(pos.toPoint()));
+ QMutableEventPoint::setPosition(touchPoint, pos);
QTouchEvent touchEvent(QEvent::TouchBegin,
touchScreenDevice,
Qt::NoModifier,
@@ -574,10 +576,10 @@ void tst_QTouchEvent::touchBeginPropagatesWhenIgnored()
// compose an event to the scene that is over the grandchild
QPointF pos = view.mapFromScene(grandchild.mapToScene(grandchild.boundingRect().center()));
- QMutableEventPoint touchPoint(0, QEventPoint::State::Pressed,
- view.mapToScene(pos.toPoint()),
- view.mapToGlobal(pos.toPoint()));
- touchPoint.setPosition(pos);
+ QEventPoint touchPoint(0, QEventPoint::State::Pressed,
+ view.mapToScene(pos.toPoint()),
+ view.mapToGlobal(pos.toPoint()));
+ QMutableEventPoint::setPosition(touchPoint, pos);
QTouchEvent touchEvent(QEvent::TouchBegin,
touchScreenDevice,
Qt::NoModifier,
@@ -657,10 +659,10 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate()
// compose an event to the scene that is over the child
QPointF pos = view.mapFromScene(grandchild.mapToScene(grandchild.boundingRect().center()));
- QMutableEventPoint touchPoint(0, QEventPoint::State::Pressed,
- view.mapToScene(pos.toPoint()),
- view.mapToGlobal(pos.toPoint()));
- touchPoint.setPosition(pos);
+ QEventPoint touchPoint(0, QEventPoint::State::Pressed,
+ view.mapToScene(pos.toPoint()),
+ view.mapToGlobal(pos.toPoint()));
+ QMutableEventPoint::setPosition(touchPoint, pos);
QTouchEvent touchBeginEvent(QEvent::TouchBegin,
touchScreenDevice,
Qt::NoModifier,
@@ -672,10 +674,10 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate()
QVERIFY(!root.seenTouchBegin);
// send the touch update to the child, but ignore it, it doesn't propagate
- touchPoint = QMutableEventPoint(0, QEventPoint::State::Updated,
- view.mapToScene(pos.toPoint()),
- view.mapToGlobal(pos.toPoint()));
- touchPoint.setPosition(pos);
+ touchPoint = QEventPoint(0, QEventPoint::State::Updated,
+ view.mapToScene(pos.toPoint()),
+ view.mapToGlobal(pos.toPoint()));
+ QMutableEventPoint::setPosition(touchPoint, pos);
QTouchEvent touchUpdateEvent(QEvent::TouchUpdate,
touchScreenDevice,
Qt::NoModifier,
@@ -687,10 +689,10 @@ void tst_QTouchEvent::touchUpdateAndEndNeverPropagate()
QVERIFY(!root.seenTouchUpdate);
// send the touch end, same thing should happen as with touch update
- touchPoint = QMutableEventPoint(0, QEventPoint::State::Released,
- view.mapToScene(pos.toPoint()),
- view.mapToGlobal(pos.toPoint()));
- touchPoint.setPosition(pos);
+ touchPoint = QEventPoint(0, QEventPoint::State::Released,
+ view.mapToScene(pos.toPoint()),
+ view.mapToGlobal(pos.toPoint()));
+ QMutableEventPoint::setPosition(touchPoint, pos);
QTouchEvent touchEndEvent(QEvent::TouchEnd,
touchScreenDevice,
Qt::NoModifier,
@@ -1025,7 +1027,7 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
// this should be translated to a TouchBegin
QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QEventPoint>() <<
- QMutableEventPoint(1234, 1, QEventPoint::State::Pressed, screenPos, screenPos, screenPos), window);
+ QMutableEventPoint::withTimeStamp(1234, 1, QEventPoint::State::Pressed, screenPos, screenPos, screenPos), window);
QWindowSystemInterface::handleTouchEvent(window, timestamp, touchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
@@ -1042,7 +1044,7 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
touchWidget.seenTouchBegin = false;
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QEventPoint>() <<
- QMutableEventPoint(1234, 10, QEventPoint::State::Pressed, screenPos, screenPos, screenPos), window);
+ QMutableEventPoint::withTimeStamp(1234, 10, QEventPoint::State::Pressed, screenPos, screenPos, screenPos), window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchEnd);
@@ -1057,7 +1059,7 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
touchWidget.seenTouchBegin = false;
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QEventPoint>() <<
- QMutableEventPoint(1234, 11, QEventPoint::State::Pressed, screenPos, screenPos, screenPos), window);
+ QMutableEventPoint::withTimeStamp(1234, 11, QEventPoint::State::Pressed, screenPos, screenPos, screenPos), window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchEnd);
@@ -1071,7 +1073,7 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
// moving the first point should translate to TouchUpdate
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QEventPoint>() <<
- QMutableEventPoint(1234, 1, QEventPoint::State::Updated, screenPos + delta, screenPos + delta, screenPos + delta), window);
+ QMutableEventPoint::withTimeStamp(1234, 1, QEventPoint::State::Updated, screenPos + delta, screenPos + delta, screenPos + delta), window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
@@ -1086,7 +1088,7 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
// releasing the first point translates to TouchEnd
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QEventPoint>() <<
- QMutableEventPoint(1234, 1, QEventPoint::State::Released, screenPos + delta + delta, screenPos + delta + delta, screenPos + delta + delta), window);
+ QMutableEventPoint::withTimeStamp(1234, 1, QEventPoint::State::Released, screenPos + delta + delta, screenPos + delta + delta, screenPos + delta + delta), window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
@@ -1110,8 +1112,8 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
touchWidget.touchEndPoints.clear();
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QEventPoint>() <<
- QMutableEventPoint(1234, 10, QEventPoint::State::Released, screenPos, screenPos, screenPos) <<
- QMutableEventPoint(1234, 11, QEventPoint::State::Stationary, screenPos, screenPos, screenPos), window);
+ QMutableEventPoint::withTimeStamp(1234, 10, QEventPoint::State::Released, screenPos, screenPos, screenPos) <<
+ QMutableEventPoint::withTimeStamp(1234, 11, QEventPoint::State::Stationary, screenPos, screenPos, screenPos), window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
@@ -1125,7 +1127,7 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
touchWidget.seenTouchEnd = false;
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QEventPoint>() <<
- QMutableEventPoint(1234, 11, QEventPoint::State::Released, screenPos + delta + delta,
+ QMutableEventPoint::withTimeStamp(1234, 11, QEventPoint::State::Released, screenPos + delta + delta,
screenPos + delta + delta, screenPos + delta + delta), window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
@@ -1140,6 +1142,14 @@ void tst_QTouchEvent::touchOnMultipleTouchscreens()
void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
{
+#ifdef Q_OS_MACOS
+#if QT_CONFIG(cursor)
+ QCursor::setPos(0, 0); // move mouse out of the way
+ if (!QTest::qWaitFor([]{ return QCursor::pos() == QPoint(0, 0); }))
+#endif
+ QSKIP("The macOS mouse cursor interferes with this test can cannot be moved away");
+#endif
+
tst_QTouchEventWidget touchWidget;
touchWidget.setObjectName("touchWidget");
touchWidget.setWindowTitle(QTest::currentTestFunction());
@@ -1160,26 +1170,27 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
touchWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
- QPointF leftPos = leftWidget.rect().center();
- QPointF rightPos = rightWidget.rect().center();
- QPointF centerPos = touchWidget.rect().center();
- QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint());
- QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint());
- QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint());
+ const QPointF leftPos = leftWidget.rect().center();
+ const QPointF rightPos = rightWidget.rect().center();
+ const QPointF centerPos = touchWidget.rect().center();
+ const QPointF leftScreenPos = leftWidget.mapToGlobal(leftPos.toPoint());
+ const QPointF rightScreenPos = rightWidget.mapToGlobal(rightPos.toPoint());
+ const QPointF centerScreenPos = touchWidget.mapToGlobal(centerPos.toPoint());
ulong timestamp = 0;
- QList<QMutableEventPoint> rawTouchPoints;
- rawTouchPoints.append(QMutableEventPoint(0));
- rawTouchPoints.append(QMutableEventPoint(1));
+ QList<QEventPoint> rawTouchPoints = {
+ QEventPoint(0),
+ QEventPoint(1),
+ };
// generate TouchBegin on leftWidget only
{
- QMutableEventPoint &tp0 = QMutableEventPoint::from(rawTouchPoints[0]);
- tp0.setState(QEventPoint::State::Pressed);
- tp0.setGlobalPosition(leftScreenPos);
- QMutableEventPoint & tp1 = QMutableEventPoint::from(rawTouchPoints[1]);
- tp1.setState(QEventPoint::State::Pressed);
- tp1.setGlobalPosition(rightScreenPos);
+ QEventPoint &tp0 = rawTouchPoints[0];
+ QMutableEventPoint::setState(tp0, QEventPoint::State::Pressed);
+ QMutableEventPoint::setGlobalPosition(tp0, leftScreenPos);
+ QEventPoint &tp1 = rawTouchPoints[1];
+ QMutableEventPoint::setState(tp1, QEventPoint::State::Pressed);
+ QMutableEventPoint::setGlobalPosition(tp1, rightScreenPos);
}
QWindow *window = touchWidget.windowHandle();
QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
@@ -1240,10 +1251,10 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
}
// generate TouchUpdate on leftWidget
- rawTouchPoints[0].setState(QEventPoint::State::Updated);
- rawTouchPoints[0].setGlobalPosition(centerScreenPos);
- rawTouchPoints[1].setState(QEventPoint::State::Updated);
- rawTouchPoints[1].setGlobalPosition(centerScreenPos);
+ QMutableEventPoint::setState(rawTouchPoints[0], QEventPoint::State::Updated);
+ QMutableEventPoint::setGlobalPosition(rawTouchPoints[0], centerScreenPos);
+ QMutableEventPoint::setState(rawTouchPoints[1], QEventPoint::State::Updated);
+ QMutableEventPoint::setGlobalPosition(rawTouchPoints[1], centerScreenPos);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchPadDevice, nativeTouchPoints);
@@ -1304,8 +1315,8 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
// generate TouchEnd on leftWidget
// both touchpoints are still at centerScreenPos
- rawTouchPoints[0].setState(QEventPoint::State::Released);
- rawTouchPoints[1].setState(QEventPoint::State::Released);
+ QMutableEventPoint::setState(rawTouchPoints[0], QEventPoint::State::Released);
+ QMutableEventPoint::setState(rawTouchPoints[1], QEventPoint::State::Released);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchPadDevice, nativeTouchPoints);
@@ -1382,17 +1393,17 @@ void tst_QTouchEvent::basicRawEventTranslationOfIds()
screenPos << touchWidget.mapToGlobal(pos[i].toPoint());
}
QPointF delta(10, 10);
- QList<QMutableEventPoint> rawTouchPoints;
+ QList<QEventPoint> rawTouchPoints;
// Press both points, this should be translated to a TouchBegin
for (int i = 0; i < 2; ++i) {
- QMutableEventPoint rawTouchPoint(i);
- rawTouchPoint.setState(QEventPoint::State::Pressed);
- rawTouchPoint.setGlobalPosition(screenPos[i]);
+ QEventPoint rawTouchPoint(i);
+ QMutableEventPoint::setState(rawTouchPoint, QEventPoint::State::Pressed);
+ QMutableEventPoint::setGlobalPosition(rawTouchPoint, screenPos[i]);
rawTouchPoints << rawTouchPoint;
}
- QMutableEventPoint &p0 = rawTouchPoints[0];
- QMutableEventPoint &p1 = rawTouchPoints[1];
+ QEventPoint &p0 = rawTouchPoints[0];
+ QEventPoint &p1 = rawTouchPoints[1];
ulong timestamp = 1234;
QWindow *window = touchWidget.windowHandle();
@@ -1414,8 +1425,8 @@ void tst_QTouchEvent::basicRawEventTranslationOfIds()
// moving the point should translate to TouchUpdate
for (int i = 0; i < rawTouchPoints.count(); ++i) {
auto &p = rawTouchPoints[i];
- p.setState(QEventPoint::State::Updated);
- p.setGlobalPosition(p.globalPosition() + delta);
+ QMutableEventPoint::setState(p, QEventPoint::State::Updated);
+ QMutableEventPoint::setGlobalPosition(p, p.globalPosition() + delta);
}
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
@@ -1429,8 +1440,8 @@ void tst_QTouchEvent::basicRawEventTranslationOfIds()
QCOMPARE(touchWidget.touchUpdatePoints.at(1).id(), 1);
// release last point
- p0.setState(QEventPoint::State::Stationary);
- p1.setState(QEventPoint::State::Released);
+ QMutableEventPoint::setState(p0, QEventPoint::State::Stationary);
+ QMutableEventPoint::setState(p1, QEventPoint::State::Released);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
@@ -1444,8 +1455,8 @@ void tst_QTouchEvent::basicRawEventTranslationOfIds()
QCOMPARE(touchWidget.touchUpdatePoints[1].id(), 1);
// Press last point again, id should increase
- p1.setState(QEventPoint::State::Pressed);
- p1.setId(42); // new id
+ QMutableEventPoint::setState(p1, QEventPoint::State::Pressed);
+ QMutableEventPoint::setId(p1, 42); // new id
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
@@ -1458,8 +1469,8 @@ void tst_QTouchEvent::basicRawEventTranslationOfIds()
QCOMPARE(touchWidget.touchUpdatePoints[1].id(), 42);
// release everything
- p0.setState(QEventPoint::State::Released);
- p1.setState(QEventPoint::State::Released);
+ QMutableEventPoint::setState(p0, QEventPoint::State::Released);
+ QMutableEventPoint::setState(p1, QEventPoint::State::Released);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
@@ -1552,23 +1563,23 @@ void tst_QTouchEvent::deleteInEventHandler()
view.resize(200, 200);
view.fitInView(scene.sceneRect());
- QMutableEventPoint touchPoint(0);
- touchPoint.setState(QEventPoint::State::Pressed);
- touchPoint.setPosition(view.mapFromScene(child1->mapToScene(child1->boundingRect().center())));
- touchPoint.setGlobalPosition(view.mapToGlobal(touchPoint.position().toPoint()));
- touchPoint.setScenePosition(view.mapToScene(touchPoint.position().toPoint()));
+ QEventPoint touchPoint(0);
+ QMutableEventPoint::setState(touchPoint, QEventPoint::State::Pressed);
+ QMutableEventPoint::setPosition(touchPoint, view.mapFromScene(child1->mapToScene(child1->boundingRect().center())));
+ QMutableEventPoint::setGlobalPosition(touchPoint, view.mapToGlobal(touchPoint.position().toPoint()));
+ QMutableEventPoint::setScenePosition(touchPoint, view.mapToScene(touchPoint.position().toPoint()));
QTouchEvent touchBeginEvent(QEvent::TouchBegin,
touchScreenDevice,
Qt::NoModifier,
{touchPoint});
- touchPoint.detach();
- touchPoint.setState(QEventPoint::State::Updated);
+ QMutableEventPoint::detach(touchPoint);
+ QMutableEventPoint::setState(touchPoint, QEventPoint::State::Updated);
QTouchEvent touchUpdateEvent(QEvent::TouchUpdate,
touchScreenDevice,
Qt::NoModifier,
{touchPoint});
- touchPoint.detach();
- touchPoint.setState(QEventPoint::State::Released);
+ QMutableEventPoint::detach(touchPoint);
+ QMutableEventPoint::setState(touchPoint, QEventPoint::State::Released);
QTouchEvent touchEndEvent(QEvent::TouchEnd,
touchScreenDevice,
Qt::NoModifier,
@@ -1648,16 +1659,17 @@ void tst_QTouchEvent::deleteInRawEventTranslation()
QPointF rightScreenPos = rightWidget->mapToGlobal(rightPos.toPoint());
ulong timestamp = 0;
- QList<QMutableEventPoint> rawTouchPoints;
- rawTouchPoints.append(QMutableEventPoint(0));
- rawTouchPoints.append(QMutableEventPoint(1));
- rawTouchPoints.append(QMutableEventPoint(2));
- rawTouchPoints[0].setState(QEventPoint::State::Pressed);
- rawTouchPoints[0].setGlobalPosition(leftScreenPos);
- rawTouchPoints[1].setState(QEventPoint::State::Pressed);
- rawTouchPoints[1].setGlobalPosition(centerScreenPos);
- rawTouchPoints[2].setState(QEventPoint::State::Pressed);
- rawTouchPoints[2].setGlobalPosition(rightScreenPos);
+ QList<QEventPoint> rawTouchPoints = {
+ QEventPoint(0),
+ QEventPoint(1),
+ QEventPoint(2),
+ };
+ QMutableEventPoint::setState(rawTouchPoints[0], QEventPoint::State::Pressed);
+ QMutableEventPoint::setGlobalPosition(rawTouchPoints[0], leftScreenPos);
+ QMutableEventPoint::setState(rawTouchPoints[1], QEventPoint::State::Pressed);
+ QMutableEventPoint::setGlobalPosition(rawTouchPoints[1], centerScreenPos);
+ QMutableEventPoint::setState(rawTouchPoints[2], QEventPoint::State::Pressed);
+ QMutableEventPoint::setGlobalPosition(rawTouchPoints[2], rightScreenPos);
// generate begin events on all widgets, the left widget should die
QWindow *window = touchWidget.windowHandle();
@@ -1670,18 +1682,18 @@ void tst_QTouchEvent::deleteInRawEventTranslation()
QVERIFY(!rightWidget.isNull());
// generate update events on all widget, the center widget should die
- rawTouchPoints[0].setState(QEventPoint::State::Updated);
- rawTouchPoints[1].setState(QEventPoint::State::Updated);
- rawTouchPoints[2].setState(QEventPoint::State::Updated);
+ QMutableEventPoint::setState(rawTouchPoints[0], QEventPoint::State::Updated);
+ QMutableEventPoint::setState(rawTouchPoints[1], QEventPoint::State::Updated);
+ QMutableEventPoint::setState(rawTouchPoints[2], QEventPoint::State::Updated);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
// generate end events on all widget, the right widget should die
- rawTouchPoints[0].setState(QEventPoint::State::Released);
- rawTouchPoints[1].setState(QEventPoint::State::Released);
- rawTouchPoints[2].setState(QEventPoint::State::Released);
+ QMutableEventPoint::setState(rawTouchPoints[0], QEventPoint::State::Released);
+ QMutableEventPoint::setState(rawTouchPoints[1], QEventPoint::State::Released);
+ QMutableEventPoint::setState(rawTouchPoints[2], QEventPoint::State::Released);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(rawTouchPoints, window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
index 67ea378c66..46d6f5bf44 100644
--- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
+++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
@@ -110,6 +110,7 @@ private slots:
void generatedMouseMove();
void keepPendingUpdateRequests();
void activateDeactivateEvent();
+ void qobject_castOnDestruction();
private:
QPoint m_availableTopLeft;
@@ -1602,6 +1603,23 @@ void tst_QWindow::sizes()
QCOMPARE(maximumHeightSpy.count(), 1);
}
+class CloseOnCloseEventWindow : public QWindow
+{
+public:
+ inline static int closeEvents;
+ CloseOnCloseEventWindow() { closeEvents = 0; }
+
+protected:
+ void closeEvent(QCloseEvent *e) override
+ {
+ if (++closeEvents > 1)
+ return;
+
+ close();
+ e->accept();
+ }
+};
+
void tst_QWindow::close()
{
{
@@ -1683,6 +1701,16 @@ void tst_QWindow::close()
QVERIFY(c.handle());
}
}
+
+ {
+ // A QWidget will call close() from the destructor, and
+ // we allow widgets deleting itself in the closeEvent,
+ // so we need to guard against close being called recursively.
+ CloseOnCloseEventWindow w;
+ w.create();
+ w.close();
+ QCOMPARE(CloseOnCloseEventWindow::closeEvents, 1);
+ }
}
void tst_QWindow::activateAndClose()
@@ -2674,6 +2702,9 @@ void tst_QWindow::keepPendingUpdateRequests()
void tst_QWindow::activateDeactivateEvent()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::WindowActivation))
+ QSKIP("QWindow::requestActivate() is not supported.");
+
class Window : public QWindow
{
public:
@@ -2714,6 +2745,19 @@ void tst_QWindow::activateDeactivateEvent()
QCOMPARE(w2.activateCount, 1);
}
+// Test that in a slot connected to destroyed() the emitter is
+// is no longer a QWindow.
+void tst_QWindow::qobject_castOnDestruction()
+{
+ QWindow window;
+ QObject::connect(&window, &QObject::destroyed, [](QObject *object)
+ {
+ QVERIFY(!qobject_cast<QWindow *>(object));
+ QVERIFY(!dynamic_cast<QWindow *>(object));
+ QVERIFY(!object->isWindowType());
+ });
+}
+
#include <tst_qwindow.moc>
QTEST_MAIN(tst_QWindow)
diff --git a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp
index 4229fa1017..e37480f633 100644
--- a/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp
+++ b/tests/auto/gui/math3d/qquaternion/tst_qquaternion.cpp
@@ -1110,6 +1110,35 @@ void tst_QQuaternion::fromEulerAngles_data()
QTest::newRow("complex")
<< 30.0f << 240.0f << -45.0f << QQuaternion(-0.531976f, -0.43968f, 0.723317f, -0.02226f);
+
+ // Three gimbal_lock cases are not unique for the conversions from quaternion
+ // to euler, Qt will use only XY rotations for these cases.
+ // For example, QQuaternion(0.5f, 0.5f, -0.5f, 0.5f) can be EulerXYZ(90.0f, 0.0f, 90.0f), too.
+ // But Qt will always convert it to EulerXYZ(90.0f, -90.0f, 0.0f) without Z-rotation.
+ QTest::newRow("gimbal_lock_1")
+ << 90.0f << -90.0f << 0.0f << QQuaternion(0.5f, 0.5f, -0.5f, 0.5f);
+
+ QTest::newRow("gimbal_lock_2")
+ << 90.0f << 40.0f << 0.0f << QQuaternion(0.664463f, 0.664463f, 0.241845f, -0.241845f);
+
+ QTest::newRow("gimbal_lock_3") << 90.0f << 170.0f << 0.0f
+ << QQuaternion(0.0616285f, 0.0616285f, 0.704416f, -0.704416f);
+
+ // These four examples have a fraction of errors that would bypass normalize() threshold
+ // and could make Gimbal lock detection fail.
+ QTest::newRow("gimbal_lock_fraction_1")
+ << -90.0f << 90.001152f << 0.0f << QQuaternion(0.499989986f, -0.5f, 0.5f, 0.5f);
+
+ QTest::newRow("gimbal_lock_fraction_2")
+ << -90.0f << -179.999985f << 0.0f
+ << QQuaternion(1.00000001e-07f, 1.00000001e-10f, -0.707106769f, -0.707105756f);
+
+ QTest::newRow("gimbal_lock_fraction_3")
+ << -90.0f << 90.0011597f << 0.0f << QQuaternion(0.499989986f, -0.49999994f, 0.5f, 0.5f);
+
+ QTest::newRow("gimbal_lock_fraction_4")
+ << -90.0f << -180.0f << 0.0f
+ << QQuaternion(9.99999996e-12f, 9.99999996e-12f, -0.707106769f, -0.707096756f);
}
void tst_QQuaternion::fromEulerAngles()
{
diff --git a/tests/auto/gui/painting/qpainter/testdata.qrc b/tests/auto/gui/painting/qpainter/testdata.qrc
deleted file mode 100644
index a7b8c222e5..0000000000
--- a/tests/auto/gui/painting/qpainter/testdata.qrc
+++ /dev/null
@@ -1,186 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>task217400.png</file>
- <file>drawEllipse/10x10SizeAt0x0.png</file>
- <file>drawEllipse/10x10SizeAt100x100.png</file>
- <file>drawEllipse/10x10SizeAt200x200.png</file>
- <file>drawEllipse/13x100SizeAt0x0.png</file>
- <file>drawEllipse/13x100SizeAt100x100.png</file>
- <file>drawEllipse/13x100SizeAt200x200.png</file>
- <file>drawEllipse/200x200SizeAt0x0.png</file>
- <file>drawEllipse/200x200SizeAt100x100.png</file>
- <file>drawEllipse/200x200SizeAt200x200.png</file>
- <file>drawLine_rop_bitmap/dst.xbm</file>
- <file>drawLine_rop_bitmap/res/res_AndNotROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_AndROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_ClearROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_CopyROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NandROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NopROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NorROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NotAndROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NotCopyROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NotOrROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NotROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_NotXorROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_OrNotROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_OrROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_SetROP.xbm</file>
- <file>drawLine_rop_bitmap/res/res_XorROP.xbm</file>
- <file>drawPixmap_rop/dst1.png</file>
- <file>drawPixmap_rop/dst2.png</file>
- <file>drawPixmap_rop/dst3.png</file>
- <file>drawPixmap_rop/src1.xbm</file>
- <file>drawPixmap_rop/src2-mask.xbm</file>
- <file>drawPixmap_rop/src2.xbm</file>
- <file>drawPixmap_rop/src3.xbm</file>
- <file>drawPixmap_rop/res/res_AndNotROP0.png</file>
- <file>drawPixmap_rop/res/res_AndNotROP1.png</file>
- <file>drawPixmap_rop/res/res_AndNotROP2.png</file>
- <file>drawPixmap_rop/res/res_AndNotROP3.png</file>
- <file>drawPixmap_rop/res/res_AndNotROP4.png</file>
- <file>drawPixmap_rop/res/res_AndNotROP5.png</file>
- <file>drawPixmap_rop/res/res_AndNotROP6.png</file>
- <file>drawPixmap_rop/res/res_AndNotROP7.png</file>
- <file>drawPixmap_rop/res/res_AndROP0.png</file>
- <file>drawPixmap_rop/res/res_AndROP1.png</file>
- <file>drawPixmap_rop/res/res_AndROP2.png</file>
- <file>drawPixmap_rop/res/res_AndROP3.png</file>
- <file>drawPixmap_rop/res/res_AndROP4.png</file>
- <file>drawPixmap_rop/res/res_AndROP5.png</file>
- <file>drawPixmap_rop/res/res_AndROP6.png</file>
- <file>drawPixmap_rop/res/res_AndROP7.png</file>
- <file>drawPixmap_rop/res/res_ClearROP0.png</file>
- <file>drawPixmap_rop/res/res_ClearROP1.png</file>
- <file>drawPixmap_rop/res/res_ClearROP2.png</file>
- <file>drawPixmap_rop/res/res_ClearROP3.png</file>
- <file>drawPixmap_rop/res/res_ClearROP4.png</file>
- <file>drawPixmap_rop/res/res_ClearROP5.png</file>
- <file>drawPixmap_rop/res/res_ClearROP6.png</file>
- <file>drawPixmap_rop/res/res_ClearROP7.png</file>
- <file>drawPixmap_rop/res/res_CopyROP0.png</file>
- <file>drawPixmap_rop/res/res_CopyROP1.png</file>
- <file>drawPixmap_rop/res/res_CopyROP2.png</file>
- <file>drawPixmap_rop/res/res_CopyROP3.png</file>
- <file>drawPixmap_rop/res/res_CopyROP4.png</file>
- <file>drawPixmap_rop/res/res_CopyROP5.png</file>
- <file>drawPixmap_rop/res/res_CopyROP6.png</file>
- <file>drawPixmap_rop/res/res_CopyROP7.png</file>
- <file>drawPixmap_rop/res/res_NandROP0.png</file>
- <file>drawPixmap_rop/res/res_NandROP1.png</file>
- <file>drawPixmap_rop/res/res_NandROP2.png</file>
- <file>drawPixmap_rop/res/res_NandROP3.png</file>
- <file>drawPixmap_rop/res/res_NandROP4.png</file>
- <file>drawPixmap_rop/res/res_NandROP5.png</file>
- <file>drawPixmap_rop/res/res_NandROP6.png</file>
- <file>drawPixmap_rop/res/res_NandROP7.png</file>
- <file>drawPixmap_rop/res/res_NopROP0.png</file>
- <file>drawPixmap_rop/res/res_NopROP1.png</file>
- <file>drawPixmap_rop/res/res_NopROP2.png</file>
- <file>drawPixmap_rop/res/res_NopROP3.png</file>
- <file>drawPixmap_rop/res/res_NopROP4.png</file>
- <file>drawPixmap_rop/res/res_NopROP5.png</file>
- <file>drawPixmap_rop/res/res_NopROP6.png</file>
- <file>drawPixmap_rop/res/res_NopROP7.png</file>
- <file>drawPixmap_rop/res/res_NorROP0.png</file>
- <file>drawPixmap_rop/res/res_NorROP1.png</file>
- <file>drawPixmap_rop/res/res_NorROP2.png</file>
- <file>drawPixmap_rop/res/res_NorROP3.png</file>
- <file>drawPixmap_rop/res/res_NorROP4.png</file>
- <file>drawPixmap_rop/res/res_NorROP5.png</file>
- <file>drawPixmap_rop/res/res_NorROP6.png</file>
- <file>drawPixmap_rop/res/res_NorROP7.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP0.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP1.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP2.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP3.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP4.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP5.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP6.png</file>
- <file>drawPixmap_rop/res/res_NotAndROP7.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP0.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP1.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP2.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP3.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP4.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP5.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP6.png</file>
- <file>drawPixmap_rop/res/res_NotCopyROP7.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP0.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP1.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP2.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP3.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP4.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP5.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP6.png</file>
- <file>drawPixmap_rop/res/res_NotOrROP7.png</file>
- <file>drawPixmap_rop/res/res_NotROP0.png</file>
- <file>drawPixmap_rop/res/res_NotROP1.png</file>
- <file>drawPixmap_rop/res/res_NotROP2.png</file>
- <file>drawPixmap_rop/res/res_NotROP3.png</file>
- <file>drawPixmap_rop/res/res_NotROP4.png</file>
- <file>drawPixmap_rop/res/res_NotROP5.png</file>
- <file>drawPixmap_rop/res/res_NotROP6.png</file>
- <file>drawPixmap_rop/res/res_NotROP7.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP0.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP1.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP2.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP3.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP4.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP5.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP6.png</file>
- <file>drawPixmap_rop/res/res_NotXorROP7.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP0.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP1.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP2.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP3.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP4.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP5.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP6.png</file>
- <file>drawPixmap_rop/res/res_OrNotROP7.png</file>
- <file>drawPixmap_rop/res/res_OrROP0.png</file>
- <file>drawPixmap_rop/res/res_OrROP1.png</file>
- <file>drawPixmap_rop/res/res_OrROP2.png</file>
- <file>drawPixmap_rop/res/res_OrROP3.png</file>
- <file>drawPixmap_rop/res/res_OrROP4.png</file>
- <file>drawPixmap_rop/res/res_OrROP5.png</file>
- <file>drawPixmap_rop/res/res_OrROP6.png</file>
- <file>drawPixmap_rop/res/res_OrROP7.png</file>
- <file>drawPixmap_rop/res/res_SetROP0.png</file>
- <file>drawPixmap_rop/res/res_SetROP1.png</file>
- <file>drawPixmap_rop/res/res_SetROP2.png</file>
- <file>drawPixmap_rop/res/res_SetROP3.png</file>
- <file>drawPixmap_rop/res/res_SetROP4.png</file>
- <file>drawPixmap_rop/res/res_SetROP5.png</file>
- <file>drawPixmap_rop/res/res_SetROP6.png</file>
- <file>drawPixmap_rop/res/res_SetROP7.png</file>
- <file>drawPixmap_rop/res/res_XorROP0.png</file>
- <file>drawPixmap_rop/res/res_XorROP1.png</file>
- <file>drawPixmap_rop/res/res_XorROP2.png</file>
- <file>drawPixmap_rop/res/res_XorROP3.png</file>
- <file>drawPixmap_rop/res/res_XorROP4.png</file>
- <file>drawPixmap_rop/res/res_XorROP5.png</file>
- <file>drawPixmap_rop/res/res_XorROP6.png</file>
- <file>drawPixmap_rop/res/res_XorROP7.png</file>
- <file>drawPixmap_rop_bitmap/dst.xbm</file>
- <file>drawPixmap_rop_bitmap/src1-mask.xbm</file>
- <file>drawPixmap_rop_bitmap/src1.xbm</file>
- <file>drawPixmap_rop_bitmap/src2.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_AndNotROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_AndROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_ClearROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_CopyROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NandROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NopROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NorROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NotAndROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NotCopyROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NotOrROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NotROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_NotXorROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_OrNotROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_OrROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_SetROP.xbm</file>
- <file>drawPixmap_rop_bitmap/res/res_XorROP.xbm</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
index 45490ef815..cfcaf5b67e 100644
--- a/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
+++ b/tests/auto/gui/painting/qpainter/tst_qpainter.cpp
@@ -301,6 +301,9 @@ private slots:
void drawImageAtPointF();
void scaledDashes();
+#if QT_CONFIG(raster_fp)
+ void hdrColors();
+#endif
private:
void fillData();
@@ -5393,6 +5396,48 @@ void tst_QPainter::scaledDashes()
QVERIFY(backFound);
}
+#if QT_CONFIG(raster_fp)
+void tst_QPainter::hdrColors()
+{
+ QImage img(10, 10, QImage::Format_RGBA32FPx4_Premultiplied);
+ img.fill(Qt::transparent);
+
+ QColor color = QColor::fromRgbF(2.0f, -0.25f, 1.5f);
+ img.setPixelColor(2, 2, color);
+ QCOMPARE(img.pixelColor(2, 2), color);
+
+ {
+ QPainterPath path;
+ path.addEllipse(4, 4, 2, 2);
+ QPainter p(&img);
+ p.fillPath(path, color);
+ p.end();
+ }
+ QCOMPARE(img.pixelColor(4, 4), color);
+
+ img.fill(color);
+ QCOMPARE(img.pixelColor(8, 8), color);
+
+ QColor color2 = QColor::fromRgbF(0.0f, 1.25f, 2.5f);
+ {
+ QPainter p(&img);
+ p.fillRect(0, 0, 3, 3, color2);
+ p.end();
+ }
+ QCOMPARE(img.pixelColor(1, 1), color2);
+ QCOMPARE(img.pixelColor(4, 4), color);
+
+ QImage img2(10, 10, QImage::Format_RGBX32FPx4);
+ {
+ QPainter p(&img2);
+ p.drawImage(0, 0, img);
+ p.end();
+ }
+ QCOMPARE(img2.pixelColor(2, 2), color2);
+ QCOMPARE(img2.pixelColor(5, 5), color);
+}
+#endif
+
QTEST_MAIN(tst_QPainter)
#include "tst_qpainter.moc"
diff --git a/tests/auto/gui/rhi/qrhi/BLACKLIST b/tests/auto/gui/rhi/qrhi/BLACKLIST
index 68621ac66b..dc2bc57077 100644
--- a/tests/auto/gui/rhi/qrhi/BLACKLIST
+++ b/tests/auto/gui/rhi/qrhi/BLACKLIST
@@ -7,3 +7,13 @@ android
# Skip 3D textures with Android emulator, the sw-based GL there is no good
[threeDimTexture]
android
+# Same here, GLES 3.0 features seem hopeless
+[renderToTextureTextureArray]
+android
+# Ditto
+[renderToTextureSampleWithSeparateTextureAndSampler]
+android
+[renderToFloatTexture]
+android
+[renderToRgb10Texture]
+android
diff --git a/tests/auto/gui/rhi/qrhi/data/buildshaders.bat b/tests/auto/gui/rhi/qrhi/data/buildshaders.bat
index 0102457b8a..b2348b42f5 100644
--- a/tests/auto/gui/rhi/qrhi/data/buildshaders.bat
+++ b/tests/auto/gui/rhi/qrhi/data/buildshaders.bat
@@ -42,6 +42,7 @@ 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 simpletextured_separate.frag.qsb simpletextured_separate.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
qsb --glsl "150,120,100 es" --hlsl 50 -c --msl 12 -o textured_multiubuf.vert.qsb textured_multiubuf.vert
diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag b/tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag
new file mode 100644
index 0000000000..41b0e4f1c2
--- /dev/null
+++ b/tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag
@@ -0,0 +1,14 @@
+#version 440
+
+layout(location = 0) in vec2 uv;
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 3) uniform texture2D tex;
+layout(binding = 5) uniform sampler samp;
+
+void main()
+{
+ vec4 c = texture(sampler2D(tex, samp), uv);
+ c.rgb *= c.a;
+ fragColor = c;
+}
diff --git a/tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag.qsb b/tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag.qsb
new file mode 100644
index 0000000000..c5afe1a8eb
--- /dev/null
+++ b/tests/auto/gui/rhi/qrhi/data/simpletextured_separate.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qrhi/qrhi.qrc b/tests/auto/gui/rhi/qrhi/qrhi.qrc
deleted file mode 100644
index f161d8aad6..0000000000
--- a/tests/auto/gui/rhi/qrhi/qrhi.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>data</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
index 24d6ad2d7c..db2ee58aae 100644
--- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
+++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp
@@ -31,6 +31,8 @@
#include <QFile>
#include <QOffscreenSurface>
#include <QPainter>
+#include <qrgbafloat.h>
+#include <qrgba64.h>
#include <QtGui/private/qrhi_p.h>
#include <QtGui/private/qrhi_p_p.h>
@@ -113,8 +115,12 @@ private slots:
void renderToTextureMip();
void renderToTextureCubemapFace_data();
void renderToTextureCubemapFace();
+ void renderToTextureTextureArray_data();
+ void renderToTextureTextureArray();
void renderToTextureTexturedQuad_data();
void renderToTextureTexturedQuad();
+ void renderToTextureSampleWithSeparateTextureAndSampler_data();
+ void renderToTextureSampleWithSeparateTextureAndSampler();
void renderToTextureArrayOfTexturedQuad_data();
void renderToTextureArrayOfTexturedQuad();
void renderToTextureTexturedQuadAndUniformBuffer_data();
@@ -133,6 +139,10 @@ private slots:
void renderToWindowSimple();
void finishWithinSwapchainFrame_data();
void finishWithinSwapchainFrame();
+ void resourceUpdateBatchBufferTextureWithSwapchainFrames_data();
+ void resourceUpdateBatchBufferTextureWithSwapchainFrames();
+ void textureRenderTargetAutoRebuild_data();
+ void textureRenderTargetAutoRebuild();
void pipelineCache_data();
void pipelineCache();
@@ -145,6 +155,11 @@ private slots:
void leakedResourceDestroy_data();
void leakedResourceDestroy();
+ void renderToFloatTexture_data();
+ void renderToFloatTexture();
+ void renderToRgb10Texture_data();
+ void renderToRgb10Texture();
+
private:
void setWindowType(QWindow *window, QRhi::Implementation impl);
@@ -336,13 +351,22 @@ void tst_QRhi::create()
const int texMax = rhi->resourceLimit(QRhi::TextureSizeMax);
const int maxAtt = rhi->resourceLimit(QRhi::MaxColorAttachments);
const int framesInFlight = rhi->resourceLimit(QRhi::FramesInFlight);
+ const int texArrayMax = rhi->resourceLimit(QRhi::TextureArraySizeMax);
+ const int uniBufRangeMax = rhi->resourceLimit(QRhi::MaxUniformBufferRange);
+ const int maxVertexInputs = rhi->resourceLimit(QRhi::MaxVertexInputs);
+ const int maxVertexOutputs = rhi->resourceLimit(QRhi::MaxVertexOutputs);
+
QVERIFY(texMin >= 1);
QVERIFY(texMax >= texMin);
QVERIFY(maxAtt >= 1);
QVERIFY(framesInFlight >= 1);
+ if (rhi->isFeatureSupported(QRhi::TextureArrays))
+ QVERIFY(texArrayMax > 1);
+ QVERIFY(uniBufRangeMax >= 224 * 4 * 4);
+ QVERIFY(maxVertexInputs >= 8);
+ QVERIFY(maxVertexOutputs >= 8);
QVERIFY(rhi->nativeHandles());
- QVERIFY(rhi->profiler());
const QRhi::Feature features[] = {
QRhi::MultisampleTexture,
@@ -903,6 +927,8 @@ void tst_QRhi::resourceUpdateBatchBuffer()
if (rhi->isFeatureSupported(QRhi::ReadBackNonUniformBuffer))
batch->readBackBuffer(dynamicBuffer.data(), 5, 10, &readResult);
+ else
+ qDebug("Skipping verification of buffer data as ReadBackNonUniformBuffer is not supported");
QVERIFY(submitResourceUpdates(rhi.data(), batch));
@@ -1518,6 +1544,31 @@ void tst_QRhi::renderToTextureSimple_data()
rhiTestData();
}
+static QRhiGraphicsPipeline *createSimplePipeline(QRhi *rhi, QRhiShaderResourceBindings *srb, QRhiRenderPassDescriptor *rpDesc)
+{
+ std::unique_ptr<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
+ QShader vs = loadShader(":/data/simple.vert.qsb");
+ if (!vs.isValid())
+ return nullptr;
+ QShader fs = loadShader(":/data/simple.frag.qsb");
+ if (!fs.isValid())
+ return nullptr;
+ pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
+ QRhiVertexInputLayout inputLayout;
+ inputLayout.setBindings({ { 2 * sizeof(float) } });
+ inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
+ pipeline->setVertexInputLayout(inputLayout);
+ pipeline->setShaderResourceBindings(srb);
+ pipeline->setRenderPassDescriptor(rpDesc);
+ return pipeline->create() ? pipeline.release() : nullptr;
+}
+
+static const float triangleVertices[] = {
+ -1.0f, -1.0f,
+ 1.0f, -1.0f,
+ 0.0f, 1.0f
+};
+
void tst_QRhi::renderToTextureSimple()
{
QFETCH(QRhi::Implementation, impl);
@@ -1543,32 +1594,15 @@ void tst_QRhi::renderToTextureSimple()
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
- static const float vertices[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- 0.0f, 1.0f
- };
- QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
QVERIFY(vbuf->create());
- updates->uploadStaticBuffer(vbuf.data(), vertices);
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
QVERIFY(srb->create());
- QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
- QShader vs = loadShader(":/data/simple.vert.qsb");
- QVERIFY(vs.isValid());
- QShader fs = loadShader(":/data/simple.frag.qsb");
- QVERIFY(fs.isValid());
- pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({ { 2 * sizeof(float) } });
- inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
- pipeline->setVertexInputLayout(inputLayout);
- pipeline->setShaderResourceBindings(srb.data());
- pipeline->setRenderPassDescriptor(rpDesc.data());
-
- QVERIFY(pipeline->create());
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
cb->setGraphicsPipeline(pipeline.data());
@@ -1670,32 +1704,15 @@ void tst_QRhi::renderToTextureMip()
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
- static const float vertices[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- 0.0f, 1.0f
- };
- QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
QVERIFY(vbuf->create());
- updates->uploadStaticBuffer(vbuf.data(), vertices);
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
QVERIFY(srb->create());
- QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
- QShader vs = loadShader(":/data/simple.vert.qsb");
- QVERIFY(vs.isValid());
- QShader fs = loadShader(":/data/simple.frag.qsb");
- QVERIFY(fs.isValid());
- pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({ { 2 * sizeof(float) } });
- inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
- pipeline->setVertexInputLayout(inputLayout);
- pipeline->setShaderResourceBindings(srb.data());
- pipeline->setRenderPassDescriptor(rpDesc.data());
-
- QVERIFY(pipeline->create());
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
cb->setGraphicsPipeline(pipeline.data());
@@ -1792,32 +1809,15 @@ void tst_QRhi::renderToTextureCubemapFace()
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
- static const float vertices[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- 0.0f, 1.0f
- };
- QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
QVERIFY(vbuf->create());
- updates->uploadStaticBuffer(vbuf.data(), vertices);
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
QVERIFY(srb->create());
- QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
- QShader vs = loadShader(":/data/simple.vert.qsb");
- QVERIFY(vs.isValid());
- QShader fs = loadShader(":/data/simple.frag.qsb");
- QVERIFY(fs.isValid());
- pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({ { 2 * sizeof(float) } });
- inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
- pipeline->setVertexInputLayout(inputLayout);
- pipeline->setShaderResourceBindings(srb.data());
- pipeline->setRenderPassDescriptor(rpDesc.data());
-
- QVERIFY(pipeline->create());
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
cb->setGraphicsPipeline(pipeline.data());
@@ -1880,6 +1880,116 @@ void tst_QRhi::renderToTextureCubemapFace()
QFAIL("Encountered a pixel that is neither red or blue");
}
+ QVERIFY(redCount > 0 && blueCount > 0);
+ QCOMPARE(redCount + blueCount, outputSize.width());
+
+ if (rhi->isYUpInFramebuffer() == rhi->isYUpInNDC())
+ QVERIFY(redCount < blueCount); // 100, 412
+ else
+ QVERIFY(redCount > blueCount); // 412, 100
+}
+
+void tst_QRhi::renderToTextureTextureArray_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::renderToTextureTextureArray()
+{
+ 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");
+
+ if (!rhi->isFeatureSupported(QRhi::TextureArrays))
+ QSKIP("TextureArrays is not supported with this backend, skipping test");
+
+ const QSize outputSize(512, 256);
+ const int ARRAY_SIZE = 8;
+ QScopedPointer<QRhiTexture> texture(rhi->newTextureArray(QRhiTexture::RGBA8,
+ ARRAY_SIZE,
+ outputSize,
+ 1,
+ QRhiTexture::RenderTarget
+ | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(texture->create());
+
+ const int LAYER = 5; // render into element #5
+
+ QRhiColorAttachment colorAtt(texture.data());
+ colorAtt.setLayer(LAYER);
+ QRhiTextureRenderTargetDescription rtDesc(colorAtt);
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget(rtDesc));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->create());
+
+ QCOMPARE(rt->pixelSize(), texture->pixelSize());
+ QCOMPARE(rt->pixelSize(), outputSize);
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+
+ QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
+
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
+ QVERIFY(vbuf->create());
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
+
+ QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
+ QVERIFY(srb->create());
+
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
+
+ cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
+ cb->setGraphicsPipeline(pipeline.data());
+ cb->setViewport({ 0, 0, float(rt->pixelSize().width()), float(rt->pixelSize().height()) });
+ QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
+ cb->setVertexInput(0, 1, &vbindings);
+ cb->draw(3);
+
+ 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);
+ };
+ QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
+ QRhiReadbackDescription readbackDescription(texture.data());
+ readbackDescription.setLayer(LAYER);
+ readbackBatch->readBackTexture(readbackDescription, &readResult);
+
+ cb->endPass(readbackBatch);
+
+ rhi->endOffscreenFrame();
+
+ QCOMPARE(result.size(), outputSize);
+
+ if (impl == QRhi::Null)
+ return;
+
+ const int y = 100;
+ const quint32 *p = reinterpret_cast<const quint32 *>(result.constScanLine(y));
+ int x = result.width() - 1;
+ int redCount = 0;
+ int blueCount = 0;
+ const int maxFuzz = 1;
+ while (x-- >= 0) {
+ const QRgb c(*p++);
+ if (qRed(c) >= (255 - maxFuzz) && qGreen(c) == 0 && qBlue(c) == 0)
+ ++redCount;
+ else if (qRed(c) == 0 && qGreen(c) == 0 && qBlue(c) >= (255 - maxFuzz))
+ ++blueCount;
+ else
+ QFAIL("Encountered a pixel that is neither red or blue");
+ }
+
+ QVERIFY(redCount > 0 && blueCount > 0);
QCOMPARE(redCount + blueCount, outputSize.width());
if (rhi->isYUpInFramebuffer() == rhi->isYUpInNDC())
@@ -2018,6 +2128,131 @@ void tst_QRhi::renderToTextureTexturedQuad()
QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qBlue(result.pixel(214, 191)));
}
+void tst_QRhi::renderToTextureSampleWithSeparateTextureAndSampler_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::renderToTextureSampleWithSeparateTextureAndSampler()
+{
+ // Same as renderToTextureTexturedQuad but the fragment shader uses a
+ // separate image and sampler. For Vulkan/Metal/D3D11 these are natively
+ // supported. For OpenGL this exercises the auto-generated combined sampler
+ // in the GLSL code and the mapping table that gets applied at run time by
+ // the backend.
+
+ 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->create());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->create());
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+
+ QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
+
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(quadVerticesUvs)));
+ QVERIFY(vbuf->create());
+ updates->uploadStaticBuffer(vbuf.data(), quadVerticesUvs);
+
+ QScopedPointer<QRhiTexture> inputTexture(rhi->newTexture(QRhiTexture::RGBA8, inputImage.size()));
+ QVERIFY(inputTexture->create());
+ updates->uploadTexture(inputTexture.data(), inputImage);
+
+ QScopedPointer<QRhiSampler> sampler(rhi->newSampler(QRhiSampler::Nearest, QRhiSampler::Nearest, QRhiSampler::None,
+ QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge));
+ QVERIFY(sampler->create());
+
+ QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
+ srb->setBindings({
+ QRhiShaderResourceBinding::texture(3, QRhiShaderResourceBinding::FragmentStage, inputTexture.data()),
+ QRhiShaderResourceBinding::sampler(5, QRhiShaderResourceBinding::FragmentStage, sampler.data())
+ });
+ QVERIFY(srb->create());
+
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
+ pipeline->setTopology(QRhiGraphicsPipeline::TriangleStrip);
+ QShader vs = loadShader(":/data/simpletextured.vert.qsb");
+ QVERIFY(vs.isValid());
+ QShader fs = loadShader(":/data/simpletextured_separate.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->create());
+
+ 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;
+
+ if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC())
+ result = std::move(result).mirrored();
+
+ QRgb white = qRgba(255, 255, 255, 255);
+ QCOMPARE(result.pixel(79, 77), white);
+ QCOMPARE(result.pixel(124, 81), white);
+ QCOMPARE(result.pixel(128, 149), white);
+ QCOMPARE(result.pixel(120, 189), white);
+ QCOMPARE(result.pixel(116, 185), white);
+
+ QRgb empty = qRgba(0, 0, 0, 0);
+ QCOMPARE(result.pixel(11, 45), empty);
+ QCOMPARE(result.pixel(246, 202), empty);
+ QCOMPARE(result.pixel(130, 18), empty);
+ QCOMPARE(result.pixel(4, 227), empty);
+
+ QVERIFY(qGreen(result.pixel(32, 52)) > 2 * qRed(result.pixel(32, 52)));
+ QVERIFY(qGreen(result.pixel(32, 52)) > 2 * qBlue(result.pixel(32, 52)));
+ QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qRed(result.pixel(214, 191)));
+ QVERIFY(qGreen(result.pixel(214, 191)) > 2 * qBlue(result.pixel(214, 191)));
+}
+
void tst_QRhi::renderToTextureArrayOfTexturedQuad_data()
{
rhiTestData();
@@ -3064,18 +3299,13 @@ void tst_QRhi::renderToTextureIndexedDraw()
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
- static const float vertices[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- 0.0f, 1.0f
- };
static const quint16 indices[] = {
0, 1, 2
};
- QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
QVERIFY(vbuf->create());
- updates->uploadStaticBuffer(vbuf.data(), vertices);
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
QScopedPointer<QRhiBuffer> ibuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, sizeof(indices)));
QVERIFY(ibuf->create());
@@ -3084,20 +3314,8 @@ void tst_QRhi::renderToTextureIndexedDraw()
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
QVERIFY(srb->create());
- QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
- QShader vs = loadShader(":/data/simple.vert.qsb");
- QVERIFY(vs.isValid());
- QShader fs = loadShader(":/data/simple.frag.qsb");
- QVERIFY(fs.isValid());
- pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({ { 2 * sizeof(float) } });
- inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
- pipeline->setVertexInputLayout(inputLayout);
- pipeline->setShaderResourceBindings(srb.data());
- pipeline->setRenderPassDescriptor(rpDesc.data());
-
- QVERIFY(pipeline->create());
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
@@ -3204,32 +3422,15 @@ void tst_QRhi::renderToWindowSimple()
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
- static const float vertices[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- 0.0f, 1.0f
- };
- QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
QVERIFY(vbuf->create());
- updates->uploadStaticBuffer(vbuf.data(), vertices);
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
QVERIFY(srb->create());
- QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
- QShader vs = loadShader(":/data/simple.vert.qsb");
- QVERIFY(vs.isValid());
- QShader fs = loadShader(":/data/simple.frag.qsb");
- QVERIFY(fs.isValid());
- pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({ { 2 * sizeof(float) } });
- inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
- pipeline->setVertexInputLayout(inputLayout);
- pipeline->setShaderResourceBindings(srb.data());
- pipeline->setRenderPassDescriptor(rpDesc.data());
-
- QVERIFY(pipeline->create());
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
const int asyncReadbackFrames = rhi->resourceLimit(QRhi::MaxAsyncReadbackFrames);
// one frame issues the readback, then we do MaxAsyncReadbackFrames more to ensure the readback completes
@@ -3343,26 +3544,10 @@ void tst_QRhi::finishWithinSwapchainFrame()
QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
QVERIFY(srb->create());
- QScopedPointer<QRhiGraphicsPipeline> pipeline(rhi->newGraphicsPipeline());
- QShader vs = loadShader(":/data/simple.vert.qsb");
- QVERIFY(vs.isValid());
- QShader fs = loadShader(":/data/simple.frag.qsb");
- QVERIFY(fs.isValid());
- pipeline->setShaderStages({ { QRhiShaderStage::Vertex, vs }, { QRhiShaderStage::Fragment, fs } });
- QRhiVertexInputLayout inputLayout;
- inputLayout.setBindings({ { 2 * sizeof(float) } });
- inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
- pipeline->setVertexInputLayout(inputLayout);
- pipeline->setShaderResourceBindings(srb.data());
- pipeline->setRenderPassDescriptor(rpDesc.data());
- QVERIFY(pipeline->create());
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
- static const float vertices[] = {
- -1.0f, -1.0f,
- 1.0f, -1.0f,
- 0.0f, 1.0f
- };
- QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(vertices)));
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
QVERIFY(vbuf->create());
// exercise begin/endExternal() just a little bit, note ExternalContent for beginPass()
@@ -3375,7 +3560,7 @@ void tst_QRhi::finishWithinSwapchainFrame()
// times within the same frame
for (int i = 0; i < 5; ++i) {
QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
- updates->uploadStaticBuffer(vbuf.data(), vertices);
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
cb->beginPass(rt, Qt::blue, { 1.0f, 0 }, updates, QRhiCommandBuffer::ExternalContent);
@@ -3419,6 +3604,277 @@ void tst_QRhi::finishWithinSwapchainFrame()
rhi->endFrame(swapChain.data());
}
+void tst_QRhi::resourceUpdateBatchBufferTextureWithSwapchainFrames_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::resourceUpdateBatchBufferTextureWithSwapchainFrames()
+{
+ if (QGuiApplication::platformName().startsWith(QLatin1String("offscreen"), Qt::CaseInsensitive))
+ QSKIP("Offscreen: Skipping onscreen test");
+
+ 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 buffer resource updates");
+
+ QScopedPointer<QWindow> window(new QWindow);
+ setWindowType(window.data(), impl);
+
+ window->setGeometry(0, 0, 640, 480);
+ window->show();
+ QVERIFY(QTest::qWaitForWindowExposed(window.data()));
+
+ QScopedPointer<QRhiSwapChain> swapChain(rhi->newSwapChain());
+ swapChain->setWindow(window.data());
+ swapChain->setFlags(QRhiSwapChain::UsedAsTransferSource);
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(swapChain->newCompatibleRenderPassDescriptor());
+ swapChain->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(swapChain->createOrResize());
+
+ const int bufferSize = 18;
+ const char *a = "123456789";
+ const char *b = "abcdefghi";
+
+ bool readCompleted = false;
+ QRhiBufferReadbackResult readResult;
+ readResult.completed = [&readCompleted] { readCompleted = true; };
+ QRhiReadbackResult texReadResult;
+ texReadResult.completed = [&readCompleted] { readCompleted = true; };
+
+ {
+ QScopedPointer<QRhiBuffer> dynamicBuffer(rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, bufferSize));
+ QVERIFY(dynamicBuffer->create());
+
+ for (int i = 0; i < bufferSize; ++i) {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+
+ // One byte every 16.66 ms should be enough for everyone: fill up
+ // the buffer with "123456789abcdefghi", one byte in each frame.
+ if (i >= bufferSize / 2)
+ batch->updateDynamicBuffer(dynamicBuffer.data(), i, 1, b + (i - bufferSize / 2));
+ else
+ batch->updateDynamicBuffer(dynamicBuffer.data(), i, 1, a + i);
+
+ QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
+ // just clear to black, but submit the resource update
+ cb->beginPass(swapChain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, batch);
+ cb->endPass();
+
+ rhi->endFrame(swapChain.data());
+ }
+
+ {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ readCompleted = false;
+ batch->readBackBuffer(dynamicBuffer.data(), 0, bufferSize, &readResult);
+
+ QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
+ cb->beginPass(swapChain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, batch);
+ cb->endPass();
+
+ rhi->endFrame(swapChain.data());
+
+ // This is a proper, typically at least double buffered renderer (as
+ // a real swapchain is involved). readCompleted may only become true
+ // in a future frame.
+ while (!readCompleted) {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+ rhi->endFrame(swapChain.data());
+ }
+
+ QVERIFY(readResult.data.size() == bufferSize);
+ QCOMPARE(readResult.data.left(bufferSize / 2), QByteArray(a));
+ QCOMPARE(readResult.data.mid(bufferSize / 2), QByteArray(b));
+ }
+ }
+
+ // Repeat for types Immutable and Static, declare Vertex usage.
+ // This may not be readable on GLES 2.0 so skip the verification then.
+ for (QRhiBuffer::Type type : { QRhiBuffer::Immutable, QRhiBuffer::Static }) {
+ QScopedPointer<QRhiBuffer> buffer(rhi->newBuffer(type, QRhiBuffer::VertexBuffer, bufferSize));
+ QVERIFY(buffer->create());
+
+ for (int i = 0; i < bufferSize; ++i) {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ if (i >= bufferSize / 2)
+ batch->uploadStaticBuffer(buffer.data(), i, 1, b + (i - bufferSize / 2));
+ else
+ batch->uploadStaticBuffer(buffer.data(), i, 1, a + i);
+
+ QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
+ cb->beginPass(swapChain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, batch);
+ cb->endPass();
+
+ rhi->endFrame(swapChain.data());
+ }
+
+ if (rhi->isFeatureSupported(QRhi::ReadBackNonUniformBuffer)) {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ readCompleted = false;
+ batch->readBackBuffer(buffer.data(), 0, bufferSize, &readResult);
+
+ QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
+ cb->beginPass(swapChain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, batch);
+ cb->endPass();
+
+ rhi->endFrame(swapChain.data());
+
+ while (!readCompleted) {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+ rhi->endFrame(swapChain.data());
+ }
+
+ QVERIFY(readResult.data.size() == bufferSize);
+ QCOMPARE(readResult.data.left(bufferSize / 2), QByteArray(a));
+ QCOMPARE(readResult.data.mid(bufferSize / 2), QByteArray(b));
+ } else {
+ qDebug("Skipping verification of buffer data as ReadBackNonUniformBuffer is not supported");
+ }
+ }
+
+ // Now exercise a texture. Internally this is expected (with low level APIs
+ // at least) to be similar to what happens with a staic buffer: copy to host
+ // visible staging buffer, enqueue buffer-to-buffer (or here
+ // buffer-to-image) copy.
+ {
+ const int w = 234;
+ const int h = 8; // use a small height because vsync throttling is active
+ const QColor colors[] = { Qt::red, Qt::green, Qt::blue, Qt::gray, Qt::yellow, Qt::black, Qt::white, Qt::magenta };
+ QImage image(w, h, QImage::Format_RGBA8888);
+ for (int i = 0; i < h; ++i) {
+ QRgb c = colors[i].rgb();
+ uchar *p = image.scanLine(i);
+ int x = w;
+ while (x--) {
+ *p++ = qRed(c);
+ *p++ = qGreen(c);
+ *p++ = qBlue(c);
+ *p++ = qAlpha(c);
+ }
+ }
+
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, QSize(w, h), 1, QRhiTexture::UsedAsTransferSource));
+ QVERIFY(texture->create());
+
+ // fill a texture from the image, two lines at a time
+ for (int i = 0; i < h / 2; ++i) {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+
+ QRhiTextureSubresourceUploadDescription subresDesc(image);
+ subresDesc.setSourceSize(QSize(w, 2));
+ subresDesc.setSourceTopLeft(QPoint(0, i * 2));
+ subresDesc.setDestinationTopLeft(QPoint(0, i * 2));
+ QRhiTextureUploadDescription uploadDesc(QRhiTextureUploadEntry(0, 0, subresDesc));
+ batch->uploadTexture(texture.data(), uploadDesc);
+
+ QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
+ cb->beginPass(swapChain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, batch);
+ cb->endPass();
+
+ rhi->endFrame(swapChain.data());
+ }
+
+ {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+
+ QRhiResourceUpdateBatch *batch = rhi->nextResourceUpdateBatch();
+ readCompleted = false;
+ batch->readBackTexture(texture.data(), &texReadResult);
+
+ QRhiCommandBuffer *cb = swapChain->currentFrameCommandBuffer();
+ cb->beginPass(swapChain->currentFrameRenderTarget(), Qt::black, { 1.0f, 0 }, batch);
+ cb->endPass();
+
+ rhi->endFrame(swapChain.data());
+
+ while (!readCompleted) {
+ QVERIFY(rhi->beginFrame(swapChain.data()) == QRhi::FrameOpSuccess);
+ rhi->endFrame(swapChain.data());
+ }
+
+ QCOMPARE(texReadResult.pixelSize, image.size());
+ QImage wrapperImage(reinterpret_cast<const uchar *>(texReadResult.data.constData()),
+ texReadResult.pixelSize.width(), texReadResult.pixelSize.height(),
+ image.format());
+ QVERIFY(imageRGBAEquals(image, wrapperImage));
+ }
+ }
+}
+
+void tst_QRhi::textureRenderTargetAutoRebuild_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::textureRenderTargetAutoRebuild()
+{
+ 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");
+
+ // case 1: beginPass's implicit create()
+ {
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, QSize(512, 512), 1, QRhiTexture::RenderTarget));
+ QVERIFY(texture->create());
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ { texture.data() } }));
+ QScopedPointer<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.data());
+ QVERIFY(rt->create());
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+ cb->beginPass(rt.data(), Qt::red, { 1.0f, 0 });
+ cb->endPass();
+ rhi->endOffscreenFrame();
+
+ texture->setPixelSize(QSize(256, 256));
+ QVERIFY(texture->create());
+ QCOMPARE(texture->pixelSize(), QSize(256, 256));
+
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+ // no rt->create() but beginPass() does it implicitly for us
+ cb->beginPass(rt.data(), Qt::red, { 1.0f, 0 });
+ QCOMPARE(rt->pixelSize(), QSize(256, 256));
+ cb->endPass();
+ rhi->endOffscreenFrame();
+ }
+
+ // case 2: pixelSize's implicit create()
+ {
+ QSize sz(512, 512);
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA8, sz, 1, QRhiTexture::RenderTarget));
+ QVERIFY(texture->create());
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ { texture.data() } }));
+ QScopedPointer<QRhiRenderPassDescriptor> rp(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rp.data());
+ QVERIFY(rt->create());
+ QCOMPARE(rt->pixelSize(), sz);
+
+ sz = QSize(256, 256);
+ texture->setPixelSize(sz);
+ QVERIFY(texture->create());
+ QCOMPARE(rt->pixelSize(), sz);
+ }
+}
+
void tst_QRhi::srbLayoutCompatibility_data()
{
rhiTestData();
@@ -4264,5 +4720,182 @@ void tst_QRhi::leakedResourceDestroy()
// let the scoped ptr do its job with the resources
}
+void tst_QRhi::renderToFloatTexture_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::renderToFloatTexture()
+{
+ 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");
+
+ if (!rhi->isTextureFormatSupported(QRhiTexture::RGBA16F))
+ QSKIP("RGBA16F is not supported, skipping test");
+
+ const QSize outputSize(1920, 1080);
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGBA16F, outputSize, 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(texture->create());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->create());
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+
+ QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
+
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
+ QVERIFY(vbuf->create());
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
+
+ QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
+ QVERIFY(srb->create());
+
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
+
+ cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
+ cb->setGraphicsPipeline(pipeline.data());
+ cb->setViewport({ 0, 0, float(outputSize.width()), float(outputSize.height()) });
+ QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
+ cb->setVertexInput(0, 1, &vbindings);
+ cb->draw(3);
+
+ 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_RGBA16FPx4);
+ };
+ QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
+ readbackBatch->readBackTexture({ texture.data() }, &readResult);
+ cb->endPass(readbackBatch);
+
+ rhi->endOffscreenFrame();
+ QCOMPARE(result.size(), texture->pixelSize());
+
+ if (impl == QRhi::Null)
+ return;
+
+ if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC())
+ result = std::move(result).mirrored();
+
+ // Now we have a red rectangle on blue background.
+ const int y = 100;
+ const QRgbaFloat16 *p = reinterpret_cast<const QRgbaFloat16 *>(result.constScanLine(y));
+ int redCount = 0;
+ int blueCount = 0;
+ int x = result.width() - 1;
+ while (x-- >= 0) {
+ QRgbaFloat16 c = *p++;
+ if (c.red() >= 0.95f && qFuzzyIsNull(c.green()) && qFuzzyIsNull(c.blue()))
+ ++redCount;
+ else if (qFuzzyIsNull(c.red()) && qFuzzyIsNull(c.green()) && c.blue() >= 0.95f)
+ ++blueCount;
+ else
+ QFAIL("Encountered a pixel that is neither red or blue");
+ }
+ QCOMPARE(redCount + blueCount, texture->pixelSize().width());
+ QVERIFY(redCount > blueCount); // 1742 > 178
+}
+
+void tst_QRhi::renderToRgb10Texture_data()
+{
+ rhiTestData();
+}
+
+void tst_QRhi::renderToRgb10Texture()
+{
+ 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");
+
+ if (!rhi->isTextureFormatSupported(QRhiTexture::RGB10A2))
+ QSKIP("RGB10A2 is not supported, skipping test");
+
+ const QSize outputSize(1920, 1080);
+ QScopedPointer<QRhiTexture> texture(rhi->newTexture(QRhiTexture::RGB10A2, outputSize, 1,
+ QRhiTexture::RenderTarget | QRhiTexture::UsedAsTransferSource));
+ QVERIFY(texture->create());
+
+ QScopedPointer<QRhiTextureRenderTarget> rt(rhi->newTextureRenderTarget({ texture.data() }));
+ QScopedPointer<QRhiRenderPassDescriptor> rpDesc(rt->newCompatibleRenderPassDescriptor());
+ rt->setRenderPassDescriptor(rpDesc.data());
+ QVERIFY(rt->create());
+
+ QRhiCommandBuffer *cb = nullptr;
+ QVERIFY(rhi->beginOffscreenFrame(&cb) == QRhi::FrameOpSuccess);
+ QVERIFY(cb);
+
+ QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
+
+ QScopedPointer<QRhiBuffer> vbuf(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(triangleVertices)));
+ QVERIFY(vbuf->create());
+ updates->uploadStaticBuffer(vbuf.data(), triangleVertices);
+
+ QScopedPointer<QRhiShaderResourceBindings> srb(rhi->newShaderResourceBindings());
+ QVERIFY(srb->create());
+
+ QScopedPointer<QRhiGraphicsPipeline> pipeline(createSimplePipeline(rhi.data(), srb.data(), rpDesc.data()));
+ QVERIFY(pipeline);
+
+ cb->beginPass(rt.data(), Qt::blue, { 1.0f, 0 }, updates);
+ cb->setGraphicsPipeline(pipeline.data());
+ cb->setViewport({ 0, 0, float(outputSize.width()), float(outputSize.height()) });
+ QRhiCommandBuffer::VertexInput vbindings(vbuf.data(), 0);
+ cb->setVertexInput(0, 1, &vbindings);
+ cb->draw(3);
+
+ 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_A2BGR30_Premultiplied);
+ };
+ QRhiResourceUpdateBatch *readbackBatch = rhi->nextResourceUpdateBatch();
+ readbackBatch->readBackTexture({ texture.data() }, &readResult);
+ cb->endPass(readbackBatch);
+
+ rhi->endOffscreenFrame();
+ QCOMPARE(result.size(), texture->pixelSize());
+
+ if (impl == QRhi::Null)
+ return;
+
+ if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC())
+ result = std::move(result).mirrored();
+
+ // Now we have a red rectangle on blue background.
+ const int y = 100;
+ int redCount = 0;
+ int blueCount = 0;
+ const int maxFuzz = 1;
+ for (int x = 0; x < result.width(); ++x) {
+ QRgb c = result.pixel(x, y);
+ if (qRed(c) >= (255 - maxFuzz) && qGreen(c) == 0 && qBlue(c) == 0)
+ ++redCount;
+ else if (qRed(c) == 0 && qGreen(c) == 0 && qBlue(c) >= (255 - maxFuzz))
+ ++blueCount;
+ else
+ QFAIL("Encountered a pixel that is neither red or blue");
+ }
+ QCOMPARE(redCount + blueCount, texture->pixelSize().width());
+ QVERIFY(redCount > blueCount); // 1742 > 178
+}
+
#include <tst_qrhi.moc>
QTEST_MAIN(tst_QRhi)
diff --git a/tests/auto/gui/rhi/qshader/data/texture_sep.frag b/tests/auto/gui/rhi/qshader/data/texture_sep.frag
new file mode 100644
index 0000000000..368e851bb4
--- /dev/null
+++ b/tests/auto/gui/rhi/qshader/data/texture_sep.frag
@@ -0,0 +1,17 @@
+#version 440
+
+layout(location = 0) in vec2 v_texcoord;
+
+layout(location = 0) out vec4 fragColor;
+
+layout(binding = 1) uniform sampler2D combinedTexSampler;
+layout(binding = 2) uniform texture2D sepTex;
+layout(binding = 3) uniform sampler sepSampler;
+layout(binding = 4) uniform sampler sepSampler2;
+
+void main()
+{
+ fragColor = texture(sampler2D(sepTex, sepSampler), v_texcoord);
+ fragColor *= texture(sampler2D(sepTex, sepSampler2), v_texcoord);
+ fragColor *= texture(combinedTexSampler, v_texcoord);
+}
diff --git a/tests/auto/gui/rhi/qshader/data/texture_sep_v6.frag.qsb b/tests/auto/gui/rhi/qshader/data/texture_sep_v6.frag.qsb
new file mode 100644
index 0000000000..b654ee576d
--- /dev/null
+++ b/tests/auto/gui/rhi/qshader/data/texture_sep_v6.frag.qsb
Binary files differ
diff --git a/tests/auto/gui/rhi/qshader/qshader.qrc b/tests/auto/gui/rhi/qshader/qshader.qrc
deleted file mode 100644
index f161d8aad6..0000000000
--- a/tests/auto/gui/rhi/qshader/qshader.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>data</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/rhi/qshader/tst_qshader.cpp b/tests/auto/gui/rhi/qshader/tst_qshader.cpp
index 1b3d861756..cf037e6d4f 100644
--- a/tests/auto/gui/rhi/qshader/tst_qshader.cpp
+++ b/tests/auto/gui/rhi/qshader/tst_qshader.cpp
@@ -48,6 +48,7 @@ private slots:
void comparison();
void loadV4();
void manualShaderPackCreation();
+ void loadV6WithSeparateImagesAndSamplers();
};
static QShader getShader(const QString &name)
@@ -278,19 +279,19 @@ void tst_QShader::mslResourceMapping()
QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(150))));
QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(330))));
- const QShader::NativeResourceBindingMap *resMap =
+ QShader::NativeResourceBindingMap resMap =
s.nativeResourceBindingMap(QShaderKey(QShader::GlslShader, QShaderVersion(330)));
- QVERIFY(!resMap);
+ QVERIFY(resMap.isEmpty());
// The Metal shader must come with a mapping table for binding points 0
// (uniform buffer) and 1 (combined image sampler mapped to a texture and
// sampler in the shader).
resMap = s.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12)));
- QVERIFY(resMap);
+ QVERIFY(!resMap.isEmpty());
- QCOMPARE(resMap->count(), 2);
- QCOMPARE(resMap->value(0).first, 0); // mapped to native buffer index 0
- QCOMPARE(resMap->value(1), qMakePair(0, 0)); // mapped to native texture index 0 and sampler index 0
+ QCOMPARE(resMap.count(), 2);
+ QCOMPARE(resMap.value(0).first, 0); // mapped to native buffer index 0
+ QCOMPARE(resMap.value(1), qMakePair(0, 0)); // mapped to native texture index 0 and sampler index 0
}
void tst_QShader::serializeShaderDesc()
@@ -570,5 +571,38 @@ void tst_QShader::manualShaderPackCreation()
QCOMPARE(newShaderPack.shader(QShaderKey(QShader::GlslShader, QShaderVersion(120))).shader(), fs_gl);
}
+void tst_QShader::loadV6WithSeparateImagesAndSamplers()
+{
+ QShader s = getShader(QLatin1String(":/data/texture_sep_v6.frag.qsb"));
+ QVERIFY(s.isValid());
+ QCOMPARE(QShaderPrivate::get(&s)->qsbVersion, 6);
+
+ const QList<QShaderKey> availableShaders = s.availableShaders();
+ QCOMPARE(availableShaders.count(), 6);
+ QVERIFY(availableShaders.contains(QShaderKey(QShader::SpirvShader, QShaderVersion(100))));
+ QVERIFY(availableShaders.contains(QShaderKey(QShader::MslShader, QShaderVersion(12))));
+ QVERIFY(availableShaders.contains(QShaderKey(QShader::HlslShader, QShaderVersion(50))));
+ QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs))));
+ QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(120))));
+ QVERIFY(availableShaders.contains(QShaderKey(QShader::GlslShader, QShaderVersion(150))));
+
+ QShader::NativeResourceBindingMap resMap =
+ s.nativeResourceBindingMap(QShaderKey(QShader::HlslShader, QShaderVersion(50)));
+ QVERIFY(resMap.count() == 4);
+ QVERIFY(s.separateToCombinedImageSamplerMappingList(QShaderKey(QShader::HlslShader, QShaderVersion(50))).isEmpty());
+ resMap = s.nativeResourceBindingMap(QShaderKey(QShader::MslShader, QShaderVersion(12)));
+ QVERIFY(resMap.count() == 4);
+ QVERIFY(s.separateToCombinedImageSamplerMappingList(QShaderKey(QShader::MslShader, QShaderVersion(12))).isEmpty());
+
+ for (auto key : {
+ QShaderKey(QShader::GlslShader, QShaderVersion(100, QShaderVersion::GlslEs)),
+ QShaderKey(QShader::GlslShader, QShaderVersion(120)),
+ QShaderKey(QShader::GlslShader, QShaderVersion(150)) })
+ {
+ auto list = s.separateToCombinedImageSamplerMappingList(key);
+ QCOMPARE(list.count(), 2);
+ }
+}
+
#include <tst_qshader.moc>
QTEST_MAIN(tst_QShader)
diff --git a/tests/auto/gui/text/qcssparser/testdata.qrc b/tests/auto/gui/text/qcssparser/testdata.qrc
deleted file mode 100644
index 56e45cfbb0..0000000000
--- a/tests/auto/gui/text/qcssparser/testdata.qrc
+++ /dev/null
@@ -1,18 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>testdata/scanner/comments/input</file>
- <file>testdata/scanner/comments/output</file>
- <file>testdata/scanner/comments2/input</file>
- <file>testdata/scanner/comments2/output</file>
- <file>testdata/scanner/comments3/input</file>
- <file>testdata/scanner/comments3/output</file>
- <file>testdata/scanner/comments4/input</file>
- <file>testdata/scanner/comments4/output</file>
- <file>testdata/scanner/quotedstring/input</file>
- <file>testdata/scanner/quotedstring/output</file>
- <file>testdata/scanner/simple/input</file>
- <file>testdata/scanner/simple/output</file>
- <file>testdata/scanner/unicode/input</file>
- <file>testdata/scanner/unicode/output</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
index f51c0eab20..7c16f4aa76 100644
--- a/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
+++ b/tests/auto/gui/text/qcssparser/tst_qcssparser.cpp
@@ -886,32 +886,34 @@ public:
styleSheets.append(sheet);
}
- virtual QStringList nodeNames(NodePtr node) const override { return QStringList(reinterpret_cast<QDomElement *>(node.ptr)->tagName()); }
- virtual QString attribute(NodePtr node, const QString &name) const override { return reinterpret_cast<QDomElement *>(node.ptr)->attribute(name); }
- virtual bool hasAttribute(NodePtr node, const QString &name) const { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttribute(name); }
- virtual bool hasAttributes(NodePtr node) const override { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttributes(); }
-
- virtual bool isNullNode(NodePtr node) const override {
- return reinterpret_cast<QDomElement *>(node.ptr)->isNull();
- }
- virtual NodePtr parentNode(NodePtr node) const override {
+ QStringList nodeNames(NodePtr node) const override
+ { return QStringList(reinterpret_cast<QDomElement *>(node.ptr)->tagName()); }
+ QString attributeValue(NodePtr node, const QCss::AttributeSelector &aSel) const override
+ { return reinterpret_cast<QDomElement *>(node.ptr)->attribute(aSel.name); }
+ bool hasAttribute(NodePtr node, const QString &name) const
+ { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttribute(name); }
+ bool hasAttributes(NodePtr node) const override
+ { return reinterpret_cast<QDomElement *>(node.ptr)->hasAttributes(); }
+
+ bool isNullNode(NodePtr node) const override
+ { return reinterpret_cast<QDomElement *>(node.ptr)->isNull(); }
+ NodePtr parentNode(NodePtr node) const override {
NodePtr parent;
parent.ptr = new QDomElement(reinterpret_cast<QDomElement *>(node.ptr)->parentNode().toElement());
return parent;
}
- virtual NodePtr duplicateNode(NodePtr node) const override {
+ NodePtr duplicateNode(NodePtr node) const override {
NodePtr n;
n.ptr = new QDomElement(*reinterpret_cast<QDomElement *>(node.ptr));
return n;
}
- virtual NodePtr previousSiblingNode(NodePtr node) const override {
+ NodePtr previousSiblingNode(NodePtr node) const override {
NodePtr sibling;
sibling.ptr = new QDomElement(reinterpret_cast<QDomElement *>(node.ptr)->previousSiblingElement());
return sibling;
}
- virtual void freeNode(NodePtr node) const override {
- delete reinterpret_cast<QDomElement *>(node.ptr);
- }
+ void freeNode(NodePtr node) const override
+ { delete reinterpret_cast<QDomElement *>(node.ptr); }
private:
QDomDocument doc;
diff --git a/tests/auto/gui/text/qfont/CMakeLists.txt b/tests/auto/gui/text/qfont/CMakeLists.txt
index 05c6ca8270..6e0583bc30 100644
--- a/tests/auto/gui/text/qfont/CMakeLists.txt
+++ b/tests/auto/gui/text/qfont/CMakeLists.txt
@@ -16,6 +16,7 @@ qt_internal_add_test(tst_qfont
# Resources:
set(testfont_resource_files
+ "datastream.515"
"weirdfont.otf"
)
diff --git a/tests/auto/gui/text/qfont/datastream.515 b/tests/auto/gui/text/qfont/datastream.515
new file mode 100644
index 0000000000..acd99e7e9b
--- /dev/null
+++ b/tests/auto/gui/text/qfont/datastream.515
Binary files differ
diff --git a/tests/auto/gui/text/qfont/testfont.qrc b/tests/auto/gui/text/qfont/testfont.qrc
deleted file mode 100644
index cf51e4a2b4..0000000000
--- a/tests/auto/gui/text/qfont/testfont.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>weirdfont.otf</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/text/qfont/tst_qfont.cpp b/tests/auto/gui/text/qfont/tst_qfont.cpp
index 6bae45e5c3..e0ece40bdf 100644
--- a/tests/auto/gui/text/qfont/tst_qfont.cpp
+++ b/tests/auto/gui/text/qfont/tst_qfont.cpp
@@ -62,6 +62,7 @@ private slots:
void insertAndRemoveSubstitutions();
void serialize_data();
void serialize();
+ void deserializeQt515();
void styleName();
void defaultFamily_data();
@@ -511,6 +512,43 @@ void tst_QFont::serialize()
}
}
+void tst_QFont::deserializeQt515()
+{
+ QFile file;
+ file.setFileName(QFINDTESTDATA("datastream.515"));
+ QVERIFY(file.open(QIODevice::ReadOnly));
+
+ QFont font;
+ {
+ QDataStream stream(&file);
+ stream.setVersion(QDataStream::Qt_5_15);
+ stream >> font;
+ }
+
+ QCOMPARE(font.family(), QStringLiteral("FirstFamily"));
+ QCOMPARE(font.families().size(), 3);
+ QCOMPARE(font.families().at(0), QStringLiteral("FirstFamily"));
+ QCOMPARE(font.families().at(1), QStringLiteral("OtherFamily1"));
+ QCOMPARE(font.families().at(2), QStringLiteral("OtherFamily2"));
+ QCOMPARE(font.pointSize(), 12);
+
+ QVERIFY(file.reset());
+ QByteArray fileContent = file.readAll();
+ QByteArray serializedContent;
+ {
+ QBuffer buffer(&serializedContent);
+ QVERIFY(buffer.open(QIODevice::WriteOnly));
+
+ QDataStream stream(&buffer);
+ stream.setVersion(QDataStream::Qt_5_15);
+ stream << font;
+ }
+
+ QCOMPARE(serializedContent, fileContent);
+
+ file.close();
+}
+
void tst_QFont::styleName()
{
#if !defined(Q_OS_MAC)
diff --git a/tests/auto/gui/text/qfontdatabase/testdata.qrc b/tests/auto/gui/text/qfontdatabase/testdata.qrc
deleted file mode 100644
index a590099b20..0000000000
--- a/tests/auto/gui/text/qfontdatabase/testdata.qrc
+++ /dev/null
@@ -1,9 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>LED_REAL.TTF</file>
- <file alias="testfont.ttf">../../../shared/resources/testfont.ttf</file>
- <file alias="testfont_condensed.ttf">../../../shared/resources/testfont_condensed.ttf</file>
- <file alias="testfont_italic.ttf">../../../shared/resources/testfont_italic.ttf</file>
- <file alias="testfont_open.otf">../../../shared/resources/testfont_open.otf</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
index dd3bbde871..5a18260ffc 100644
--- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
+++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp
@@ -34,6 +34,8 @@
#include <qfontmetrics.h>
#include <qtextlayout.h>
#include <private/qrawfont_p.h>
+#include <private/qfont_p.h>
+#include <private/qfontengine_p.h>
#include <qpa/qplatformfontdatabase.h>
Q_LOGGING_CATEGORY(lcTests, "qt.text.tests")
@@ -82,6 +84,10 @@ private slots:
void stretchRespected();
+#ifdef Q_OS_WIN
+ void findCourier();
+#endif
+
private:
QString m_ledFont;
QString m_testFont;
@@ -429,7 +435,11 @@ void tst_QFontDatabase::condensedFontMatching()
tfcByStyleName.setStyleName("Condensed");
#ifdef Q_OS_WIN
- QEXPECT_FAIL("","No matching of sub-family by stretch on Windows", Continue);
+ QFont f;
+ f.setStyleStrategy(QFont::NoFontMerging);
+ QFontPrivate *font_d = QFontPrivate::get(f);
+ if (font_d->engineForScript(QChar::Script_Common)->type() != QFontEngine::Freetype)
+ QEXPECT_FAIL("","No matching of sub-family by stretch on Windows", Continue);
#endif
#ifdef Q_OS_ANDROID
@@ -494,5 +504,32 @@ void tst_QFontDatabase::registerOpenTypePreferredNamesApplication()
QFontDatabase::removeApplicationFont(id);
}
+#ifdef Q_OS_WIN
+void tst_QFontDatabase::findCourier()
+{
+ QFont font = QFontDatabase::font(u"Courier"_qs, u""_qs, 16);
+ QFontInfo info(font);
+ QCOMPARE(info.family(), u"Courier New"_qs);
+ QCOMPARE(info.pointSize(), 16);
+
+ font = QFontDatabase::font("Courier", "", 64);
+ info = font;
+ QCOMPARE(info.family(), u"Courier New"_qs);
+ QCOMPARE(info.pointSize(), 64);
+
+ // By setting "PreferBitmap" we should get Courier itself.
+ font.setStyleStrategy(QFont::PreferBitmap);
+ info = font;
+ QCOMPARE(info.family(), u"Courier"_qs);
+ // Which has an upper bound on point size
+ QCOMPARE(info.pointSize(), 19);
+
+ font.setStyleStrategy(QFont::PreferDefault);
+ info = font;
+ QCOMPARE(info.family(), u"Courier New"_qs);
+ QCOMPARE(info.pointSize(), 64);
+}
+#endif
+
QTEST_MAIN(tst_QFontDatabase)
#include "tst_qfontdatabase.moc"
diff --git a/tests/auto/gui/text/qfontmetrics/testfont.qrc b/tests/auto/gui/text/qfontmetrics/testfont.qrc
deleted file mode 100644
index 30b4a3f82e..0000000000
--- a/tests/auto/gui/text/qfontmetrics/testfont.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource prefix="/fonts">
- <file>ucs4font.ttf</file>
- <file alias="testfont.ttf">../../../shared/resources/testfont.ttf</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp
index c78475a76f..f6700eb43a 100644
--- a/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp
+++ b/tests/auto/gui/text/qfontmetrics/tst_qfontmetrics.cpp
@@ -43,6 +43,7 @@ private slots:
void same();
void metrics();
void boundingRect();
+ void boundingRect2();
void elidedText_data();
void elidedText();
void veryNarrowElidedText();
@@ -56,6 +57,8 @@ private slots:
void leadingBelowLine();
void elidedMetrics();
void zeroWidthMetrics();
+ void verticalMetrics_data();
+ void verticalMetrics();
};
void tst_QFontMetrics::same()
@@ -149,6 +152,21 @@ void tst_QFontMetrics::boundingRect()
QVERIFY(r.top() < 0);
}
+void tst_QFontMetrics::boundingRect2()
+{
+ QFont f;
+ f.setPixelSize(16);
+ QFontMetricsF fm(f);
+ QString str("AVAVAVA vvvvvvvvvv fffffffff file");
+ QRectF br = fm.boundingRect(str);
+ QRectF tbr = fm.tightBoundingRect(str);
+ qreal advance = fm.horizontalAdvance(str);
+ // Bounding rect plus bearings should be similar to advance
+ qreal bearings = fm.leftBearing(QChar('A')) + fm.rightBearing(QChar('e'));
+ QVERIFY(qAbs(br.width() + bearings - advance) < fm.averageCharWidth()/2.0);
+ QVERIFY(qAbs(tbr.width() + bearings - advance) < fm.averageCharWidth()/2.0);
+}
+
void tst_QFontMetrics::elidedText_data()
{
QTest::addColumn<QFont>("font");
@@ -374,6 +392,25 @@ void tst_QFontMetrics::zeroWidthMetrics()
QCOMPARE(fm.horizontalAdvance(string3), fm.horizontalAdvance(string4));
QCOMPARE(fm.boundingRect(string1).width(), fm.boundingRect(string2).width());
QCOMPARE(fm.boundingRect(string3).width(), fm.boundingRect(string4).width());
+ QCOMPARE(fm.tightBoundingRect(string1).width(), fm.tightBoundingRect(string2).width());
+ QCOMPARE(fm.tightBoundingRect(string3).width(), fm.tightBoundingRect(string4).width());
+}
+
+void tst_QFontMetrics::verticalMetrics_data()
+{
+ QTest::addColumn<QFont>("font");
+ QStringList families = QFontDatabase::families();
+ for (const QString &family : families) {
+ QFont font(family);
+ QTest::newRow(family.toUtf8()) << font;
+ }
+}
+
+void tst_QFontMetrics::verticalMetrics()
+{
+ QFETCH(QFont, font);
+ QFontMetrics fm(font);
+ QVERIFY(fm.ascent() != 0 || fm.descent() != 0);
}
QTEST_MAIN(tst_QFontMetrics)
diff --git a/tests/auto/gui/text/qglyphrun/testdata.qrc b/tests/auto/gui/text/qglyphrun/testdata.qrc
deleted file mode 100644
index 25cadc477e..0000000000
--- a/tests/auto/gui/text/qglyphrun/testdata.qrc
+++ /dev/null
@@ -1,5 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file alias="test.ttf">../../../shared/resources/test.ttf</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/text/qrawfont/testdata.qrc b/tests/auto/gui/text/qrawfont/testdata.qrc
deleted file mode 100644
index c7ac9641d1..0000000000
--- a/tests/auto/gui/text/qrawfont/testdata.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>testfont_bold_italic.ttf</file>
- <file>testfont_os2_v1.ttf</file>
- <file alias="testfont.ttf">../../../shared/resources/testfont.ttf</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
index c028ae1b9c..bb2f3750aa 100644
--- a/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
+++ b/tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
@@ -96,6 +96,7 @@ private slots:
void toHtml2();
void setFragmentMarkersInHtmlExport();
+ void setMediaRule();
void toHtmlBodyBgColor();
void toHtmlBodyBgColorRgba();
@@ -198,6 +199,12 @@ private slots:
void resourceProvider();
+ void contentsChangeIndices_data();
+ void contentsChangeIndices();
+
+ void insertHtmlWithComments_data();
+ void insertHtmlWithComments();
+
private:
void backgroundImage_checkExpectedHtml(const QTextDocument &doc);
void buildRegExpData();
@@ -1907,6 +1914,39 @@ void tst_QTextDocument::setFragmentMarkersInHtmlExport()
}
}
+void tst_QTextDocument::setMediaRule()
+{
+ {
+ CREATE_DOC_AND_CURSOR();
+ doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }");
+ doc.setHtml("<p>Hello World</p>");
+
+ QString expected = htmlHead;
+ expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#000000;\"><span style=\" background-color:#000000;\">Hello World</span></p>") + htmlTail;
+ QCOMPARE(doc.toHtml(), expected);
+ }
+ {
+ CREATE_DOC_AND_CURSOR();
+ doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }");
+ doc.setMetaInformation(QTextDocument::CssMedia, "screen");
+ doc.setHtml("<p>Hello World</p>");
+
+ QString expected = htmlHead;
+ expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#000000;\"><span style=\" background-color:#000000;\">Hello World</span></p>") + htmlTail;
+ QCOMPARE(doc.toHtml(), expected);
+ }
+ {
+ CREATE_DOC_AND_CURSOR();
+ doc.setDefaultStyleSheet("@media screen { p { background:#000000 } } @media print { p { background:#ffffff } }");
+ doc.setMetaInformation(QTextDocument::CssMedia, "print");
+ doc.setHtml("<p>Hello World</p>");
+
+ QString expected = htmlHead;
+ expected += QString("<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; background-color:#ffffff;\"><span style=\" background-color:#ffffff;\">Hello World</span></p>") + htmlTail;
+ QCOMPARE(doc.toHtml(), expected);
+ }
+}
+
void tst_QTextDocument::toHtmlBodyBgColor()
{
CREATE_DOC_AND_CURSOR();
@@ -2291,14 +2331,18 @@ void tst_QTextDocument::clonePreservesMetaInformation()
{
const QString title("Foobar");
const QString url("about:blank");
+ const QString media("print");
doc->setHtml("<html><head><title>" + title + "</title></head><body>Hrm</body></html>");
doc->setMetaInformation(QTextDocument::DocumentUrl, url);
+ doc->setMetaInformation(QTextDocument::CssMedia, media);
QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), title);
QCOMPARE(doc->metaInformation(QTextDocument::DocumentUrl), url);
+ QCOMPARE(doc->metaInformation(QTextDocument::CssMedia), media);
QTextDocument *clone = doc->clone();
QCOMPARE(clone->metaInformation(QTextDocument::DocumentTitle), title);
QCOMPARE(clone->metaInformation(QTextDocument::DocumentUrl), url);
+ QCOMPARE(clone->metaInformation(QTextDocument::CssMedia), media);
delete clone;
}
@@ -3820,5 +3864,100 @@ void tst_QTextDocument::resourceProvider()
QCOMPARE(providerCalled, 2);
}
+void tst_QTextDocument::contentsChangeIndices_data()
+{
+ QTest::addColumn<QString>("html");
+ // adding list entries change the entire block, so change position is
+ // not the same as the cursor position if this value is >= 0
+ QTest::addColumn<int>("expectedBegin");
+
+ QTest::addRow("text") << "Test" << -1;
+ QTest::addRow("unnumbered list") << "<ul><li>Test</li></ul>" << 0;
+ QTest::addRow("numbered list") << "<ol><li>Test</li></ol>" << 0;
+ QTest::addRow("table") << "<table><tr><td>Test</td></tr></table>" << -1;
+}
+
+void tst_QTextDocument::contentsChangeIndices()
+{
+ QFETCH(QString, html);
+ QFETCH(int, expectedBegin);
+
+ QTextDocument doc;
+ QTestDocumentLayout *layout = new QTestDocumentLayout(&doc);
+ doc.setDocumentLayout(layout);
+ doc.setHtml(QString("<html><body>%1</body></html>").arg(html));
+
+ int documentLength = 0;
+ int cursorLength = 0;
+ int changeBegin = 0;
+ int changeRemoved = 0;
+ int changeAdded = 0;
+ connect(&doc, &QTextDocument::contentsChange, this, [&](int pos, int removed, int added){
+ documentLength = doc.characterCount();
+
+ QTextCursor cursor(&doc);
+ cursor.movePosition(QTextCursor::End);
+ // includes end-of-paragraph character
+ cursorLength = cursor.position() + 1;
+
+ changeBegin = pos;
+ changeRemoved = removed;
+ changeAdded = added;
+ });
+
+ QTextCursor cursor(&doc);
+ cursor.movePosition(QTextCursor::End);
+ if (expectedBegin < 0)
+ expectedBegin = cursor.position();
+ cursor.insertBlock();
+
+ const int changeEnd = changeBegin + changeAdded;
+
+ QVERIFY(documentLength > 0);
+ QCOMPARE(documentLength, cursorLength);
+ QVERIFY(documentLength >= changeEnd);
+ QCOMPARE(changeBegin, expectedBegin);
+ QCOMPARE(changeAdded - changeRemoved, 1);
+}
+
+void tst_QTextDocument::insertHtmlWithComments_data()
+{
+ QTest::addColumn<QString>("html");
+ QTest::addColumn<QStringList>("expectedBlocks");
+
+ QTest::newRow("commentless") << "<p>first</p><p>second</p><p>third</p>"
+ << QStringList { "first", "second", "third" };
+ QTest::newRow("normal") << "<p>first</p><!--<p>second</p>--><p>third</p>"
+ << QStringList { "first", "third" };
+ QTest::newRow("nonClosing") << "<p>first</p><!--<p>second</p><p>third</p>"
+ << QStringList { "first" };
+ QTest::newRow("immediatelyClosing") << "<p>first</p><!----><p>second</p><p>third</p>"
+ << QStringList { "first", "second", "third" };
+ QTest::newRow("fake") << "<p>first</p><!-<p>second</p><p>third</p>"
+ << QStringList { "first", "second", "third" };
+ QTest::newRow("endingNonExistant") << "<p>first</p>--><p>second</p><p>third</p>"
+ << QStringList { "first", "-->", "second", "third" };
+}
+
+void tst_QTextDocument::insertHtmlWithComments()
+{
+ QFETCH(QString, html);
+ QFETCH(QStringList, expectedBlocks);
+
+ QTextDocument doc;
+ doc.setHtml(html);
+
+ QCOMPARE(doc.blockCount(), expectedBlocks.count());
+
+ QStringList blockContent;
+ auto currentBlock = doc.begin();
+ while (currentBlock != doc.end()) {
+ blockContent.append(currentBlock.text());
+ currentBlock = currentBlock.next();
+ }
+
+ QCOMPARE(blockContent, expectedBlocks);
+}
+
QTEST_MAIN(tst_QTextDocument)
#include "tst_qtextdocument.moc"
diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp
index 24704bec37..eaa29ca5f3 100644
--- a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp
+++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp
@@ -100,6 +100,7 @@ private slots:
void inheritAlignment();
void dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag();
void toPlainText();
+ void toRawText();
void copyTableRow();
void copyTableColumn();
void copySubTable();
@@ -1094,6 +1095,14 @@ void tst_QTextDocumentFragment::toPlainText()
QCOMPARE(doc->blockCount(), 3);
}
+void tst_QTextDocumentFragment::toRawText()
+{
+ // Make sure nbsp, line separator, paragraph separator is preserved
+ doc->setPlainText("Hello\u0A00\u2028\u2029World");
+
+ QCOMPARE(QTextDocumentFragment(doc).toRawText(), "Hello\u0A00\u2028\u2029World");
+}
+
void tst_QTextDocumentFragment::copyTableRow()
{
QTextDocumentFragment frag;
diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
index 4b8ba98d04..32a0374fcd 100644
--- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
+++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp
@@ -68,11 +68,15 @@ private slots:
void forcedBreaks();
void breakAny();
void noWrap();
+
void cursorToXForInlineObjects();
void cursorToXForSetColumns();
void cursorToXForTrailingSpaces_data();
void cursorToXForTrailingSpaces();
void cursorToXInvalidInput();
+ void cursorToXForBidiBoundaries_data();
+ void cursorToXForBidiBoundaries();
+
void horizontalAlignment_data();
void horizontalAlignment();
void horizontalAlignmentMultiline_data();
@@ -86,6 +90,8 @@ private slots:
#ifdef QT_BUILD_INTERNAL
void xToCursorAtEndOfLine();
#endif
+ void xToCursorForBidiEnds_data();
+ void xToCursorForBidiEnds();
void boundingRectTopLeft();
void graphemeBoundaryForSurrogatePairs();
void tabStops();
@@ -734,6 +740,58 @@ void tst_QTextLayout::cursorToXInvalidInput()
QCOMPARE(cursorPos, 3);
}
+void tst_QTextLayout::cursorToXForBidiBoundaries_data()
+{
+ QTest::addColumn<Qt::LayoutDirection>("textDirection");
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<int>("cursorPosition");
+ QTest::addColumn<int>("expectedX");
+
+ QTest::addRow("LTR, abcشزذabc, 0") << Qt::LeftToRight << "abcشزذabc"
+ << 0 << 0;
+ QTest::addRow("RTL, abcشزذabc, 9") << Qt::RightToLeft << "abcشزذabc"
+ << 9 << TESTFONT_SIZE * 3;
+ QTest::addRow("LTR, abcشزذabc, 3") << Qt::LeftToRight << "abcشزذabc"
+ << 0 << 0;
+ QTest::addRow("RTL, abcشزذabc, 6") << Qt::RightToLeft << "abcشزذabc"
+ << 9 << TESTFONT_SIZE * 3;
+
+ QTest::addRow("LTR, شزذabcشزذ, 0") << Qt::LeftToRight << "شزذabcشزذ"
+ << 0 << TESTFONT_SIZE * 2;
+ QTest::addRow("RTL, شزذabcشزذ, 9") << Qt::RightToLeft << "شزذabcشزذ"
+ << 9 << 0;
+ QTest::addRow("LTR, شزذabcشزذ, 3") << Qt::LeftToRight << "شزذabcشزذ"
+ << 3 << TESTFONT_SIZE * 2;
+ QTest::addRow("RTL, شزذabcشزذ, 3") << Qt::RightToLeft << "شزذabcشزذ"
+ << 3 << TESTFONT_SIZE * 5;
+ QTest::addRow("LTR, شزذabcشزذ, 6") << Qt::LeftToRight << "شزذabcشزذ"
+ << 6 << TESTFONT_SIZE * 5;
+ QTest::addRow("RTL, شزذabcشزذ, 6") << Qt::RightToLeft << "شزذabcشزذ"
+ << 6 << TESTFONT_SIZE * 2;
+}
+
+void tst_QTextLayout::cursorToXForBidiBoundaries()
+{
+ QFETCH(Qt::LayoutDirection, textDirection);
+ QFETCH(QString, text);
+ QFETCH(int, cursorPosition);
+ QFETCH(int, expectedX);
+
+ QTextOption option;
+ option.setTextDirection(textDirection);
+
+ QTextLayout layout(text, testFont);
+ layout.setTextOption(option);
+ layout.beginLayout();
+
+ QTextLine line = layout.createLine();
+ line.setLineWidth(0x10000);
+
+ QCOMPARE(line.cursorToX(cursorPosition), expectedX);
+
+ layout.endLayout();
+}
+
void tst_QTextLayout::horizontalAlignment_data()
{
qreal width = TESTFONT_SIZE * 4;
@@ -1126,6 +1184,60 @@ void tst_QTextLayout::xToCursorAtEndOfLine()
}
#endif
+
+void tst_QTextLayout::xToCursorForBidiEnds_data()
+{
+ QTest::addColumn<Qt::LayoutDirection>("textDirection");
+ QTest::addColumn<QString>("text");
+ QTest::addColumn<int>("leftPosition");
+ QTest::addColumn<int>("rightPosition");
+
+ QTest::addRow("LTR, abcشزذ") << Qt::LeftToRight << "abcشزذ"
+ << 0 << 6;
+ QTest::addRow("RTL, abcشزذ") << Qt::RightToLeft << "abcشزذ"
+ << 6 << 0;
+ QTest::addRow("LTR, شزذabc") << Qt::LeftToRight << "شزذabc"
+ << 0 << 6;
+ QTest::addRow("RTL, شزذabc") << Qt::RightToLeft << "شزذabc"
+ << 6 << 0;
+ QTest::addRow("LTR, شزذ123") << Qt::LeftToRight << "شزذ123"
+ << 0 << 6;
+ QTest::addRow("RTL, شزذ123") << Qt::RightToLeft << "شزذ123"
+ << 6 << 0;
+
+ QTest::addRow("LTR, abcشزذabc") << Qt::LeftToRight << "abcشزذabc"
+ << 0 << 9;
+ QTest::addRow("RTL, abcشزذabc") << Qt::RightToLeft << "abcشزذabc"
+ << 9 << 0;
+ QTest::addRow("LTR, شزذabcشزذ") << Qt::LeftToRight << "شزذabcشزذ"
+ << 0 << 9;
+ QTest::addRow("RTL, شزذabcشزذ") << Qt::RightToLeft << "شزذabcشزذ"
+ << 9 << 0;
+}
+
+void tst_QTextLayout::xToCursorForBidiEnds()
+{
+ QFETCH(Qt::LayoutDirection, textDirection);
+ QFETCH(QString, text);
+ QFETCH(int, leftPosition);
+ QFETCH(int, rightPosition);
+
+ QTextOption option;
+ option.setTextDirection(textDirection);
+
+ QTextLayout layout(text, testFont);
+ layout.setTextOption(option);
+ layout.beginLayout();
+
+ QTextLine line = layout.createLine();
+ line.setLineWidth(0x10000);
+
+ QCOMPARE(line.xToCursor(0), leftPosition);
+ QCOMPARE(line.xToCursor(line.width()), rightPosition);
+
+ layout.endLayout();
+}
+
void tst_QTextLayout::boundingRectTopLeft()
{
QString text = "FirstLine\nSecondLine";
diff --git a/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp
index 9b376c41f4..fddcf2b692 100644
--- a/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp
+++ b/tests/auto/gui/text/qtextmarkdownimporter/tst_qtextmarkdownimporter.cpp
@@ -77,6 +77,7 @@ public:
Mono = 0x10,
Link = 0x20
};
+ Q_ENUM(CharFormat)
Q_DECLARE_FLAGS(CharFormats, CharFormat)
};
@@ -211,6 +212,9 @@ void tst_QTextMarkdownImporter::lists_data()
QTest::newRow("numeric lists nested in empty lists")
<< "- \n 1. a\n 2. b\n- c\n 1.\n + d\n" << 4 << false
<< "- \n 1. a\n 2. b\n- c 1. + d\n";
+ QTest::newRow("styled spans in list items")
+ << "1. normal text\n2. **bold** text\n3. `code` in the item\n4. *italic* text\n5. _underlined_ text\n" << 5 << false
+ << "1. normal text\n2. **bold** text\n3. `code` in the item\n4. *italic* text\n5. _underlined_ text\n";
}
void tst_QTextMarkdownImporter::lists()
@@ -222,11 +226,22 @@ void tst_QTextMarkdownImporter::lists()
QTextDocument doc;
doc.setMarkdown(input); // QTBUG-78870 : don't crash
+
+#ifdef DEBUG_WRITE_HTML
+ {
+ QFile out("/tmp/" + QLatin1String(QTest::currentDataTag()) + ".html");
+ out.open(QFile::WriteOnly);
+ out.write(doc.toHtml().toLatin1());
+ out.close();
+ }
+#endif
+
QTextFrame::iterator iterator = doc.rootFrame()->begin();
QTextFrame *currentFrame = iterator.currentFrame();
int i = 0;
int itemCount = 0;
bool emptyItems = true;
+ QString firstItemFontFamily;
while (!iterator.atEnd()) {
// There are no child frames
QCOMPARE(iterator.currentFrame(), currentFrame);
@@ -239,6 +254,21 @@ void tst_QTextMarkdownImporter::lists()
}
qCDebug(lcTests, "%d %s%s", i,
(block.textList() ? "<li>" : "<p>"), qPrintable(block.text()));
+ QTextCharFormat listItemFmt = block.charFormat();
+ QFont listItemFont = listItemFmt.font();
+ // QTextDocumentLayoutPrivate::drawListItem() uses listItemFont to render numbers in an ordered list.
+ // We want that to be consistent, regardless whether the list item's text begins with a styled span.
+ if (firstItemFontFamily.isEmpty())
+ firstItemFontFamily = listItemFont.family();
+ else
+ QCOMPARE(listItemFont.family(), firstItemFontFamily);
+ QCOMPARE(listItemFont.bold(), false);
+ QCOMPARE(listItemFont.italic(), false);
+ QCOMPARE(listItemFont.underline(), false);
+ QCOMPARE(listItemFont.fixedPitch(), false);
+ QCOMPARE(listItemFmt.fontItalic(), false);
+ QCOMPARE(listItemFmt.fontUnderline(), false);
+ QCOMPARE(listItemFmt.fontFixedPitch(), false);
++iterator;
++i;
}
@@ -335,13 +365,15 @@ void tst_QTextMarkdownImporter::nestedSpans()
<< "underlined" << fmt.fontUnderline()
<< "strikeout" << fmt.fontStrikeOut() << "anchor" << fmt.isAnchor()
<< "monospace" << QFontInfo(fmt.font()).fixedPitch() // depends on installed fonts (QTBUG-75649)
- << fmt.fontFixedPitch() // returns false even when font family is "monospace"
- << fmt.hasProperty(QTextFormat::FontFixedPitch); // works
+ << fmt.fontFixedPitch()
+ << fmt.hasProperty(QTextFormat::FontFixedPitch)
+ << "expected" << expectedFormat;
QCOMPARE(fmt.fontWeight() > QFont::Normal, expectedFormat.testFlag(Bold));
QCOMPARE(fmt.fontItalic(), expectedFormat.testFlag(Italic));
QCOMPARE(fmt.fontUnderline(), expectedFormat.testFlag(Underlined));
QCOMPARE(fmt.fontStrikeOut(), expectedFormat.testFlag(Strikeout));
QCOMPARE(fmt.isAnchor(), expectedFormat.testFlag(Link));
+ QCOMPARE(fmt.fontFixedPitch(), expectedFormat.testFlag(Mono));
QCOMPARE(fmt.hasProperty(QTextFormat::FontFixedPitch), expectedFormat.testFlag(Mono));
++iterator;
}
diff --git a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
index bc6ee81ad4..24bb1a5992 100644
--- a/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
+++ b/tests/auto/gui/text/qtextmarkdownwriter/tst_qtextmarkdownwriter.cpp
@@ -51,6 +51,7 @@ private slots:
void testWriteParagraph();
void testWriteList();
void testWriteEmptyList();
+ void testWriteCheckboxListItemEndingWithCode();
void testWriteNestedBulletLists_data();
void testWriteNestedBulletLists();
void testWriteNestedNumericLists();
@@ -133,6 +134,34 @@ void tst_QTextMarkdownWriter::testWriteEmptyList()
QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1("- \n"));
}
+void tst_QTextMarkdownWriter::testWriteCheckboxListItemEndingWithCode()
+{
+ QTextCursor cursor(document);
+ QTextList *list = cursor.createList(QTextListFormat::ListDisc);
+ cursor.insertText("Image.originalSize property (not necessary; PdfDocument.pagePointSize() substitutes)");
+ list->add(cursor.block());
+ {
+ auto fmt = cursor.block().blockFormat();
+ fmt.setMarker(QTextBlockFormat::MarkerType::Unchecked);
+ cursor.setBlockFormat(fmt);
+ }
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 2);
+ cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor, 4);
+ QCOMPARE(cursor.selectedText(), QString::fromLatin1("PdfDocument.pagePointSize()"));
+ auto fmt = cursor.charFormat();
+ fmt.setFontFixedPitch(true);
+ cursor.setCharFormat(fmt);
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::MoveAnchor, 5);
+ cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor, 4);
+ QCOMPARE(cursor.selectedText(), QString::fromLatin1("Image.originalSize"));
+ cursor.setCharFormat(fmt);
+
+ QCOMPARE(documentToUnixMarkdown(), QString::fromLatin1(
+ "- [ ] `Image.originalSize` property (not necessary; `PdfDocument.pagePointSize()`\n substitutes)\n"));
+}
+
void tst_QTextMarkdownWriter::testWriteNestedBulletLists_data()
{
QTest::addColumn<bool>("checkbox");
@@ -437,9 +466,9 @@ void tst_QTextMarkdownWriter::fromHtml_data()
// QTest::newRow("escaped number and paren after double newline") <<
// "<p>(The first sentence of this paragraph is a line, the next paragraph has a number</p>13) but that's not part of an ordered list" <<
// "(The first sentence of this paragraph is a line, the next paragraph has a number\n\n13\\) but that's not part of an ordered list\n\n";
-// QTest::newRow("preformats with embedded backticks") <<
-// "<pre>none `one` ``two``</pre><pre>```three``` ````four````</pre>plain" <<
-// "``` none `one` ``two`` ```\n\n````` ```three``` ````four```` `````\n\nplain\n\n";
+ QTest::newRow("preformats with embedded backticks") <<
+ "<pre>none `one` ``two``</pre><pre>```three``` ````four````</pre>plain" <<
+ "``` none `one` ``two`` ```\n\n````` ```three``` ````four```` `````\n\nplain\n\n";
}
void tst_QTextMarkdownWriter::fromHtml()
diff --git a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
index dabe51f833..8575da04bb 100644
--- a/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
+++ b/tests/auto/gui/text/qtexttable/tst_qtexttable.cpp
@@ -29,7 +29,7 @@
#include <QTest>
-
+#include <qbuffer.h>
#include <qtextdocument.h>
#include <qtextdocumentfragment.h>
#include <qtexttable.h>
@@ -44,6 +44,7 @@
#include <QPainter>
#include <QPaintEngine>
#endif
+#include <private/qtextdocumentlayout_p.h>
#include <private/qpagedpaintdevice_p.h>
typedef QList<int> IntList;
@@ -100,6 +101,13 @@ private slots:
void checkBorderAttributes_data();
void checkBorderAttributes();
+#ifndef QT_NO_WIDGETS
+ void columnWidthWithSpans();
+
+ void columnWidthWithImage_data();
+ void columnWidthWithImage();
+#endif
+
private:
QTextTable *create2x2Table();
QTextTable *create4x4Table();
@@ -1278,5 +1286,84 @@ void tst_QTextTable::checkBorderAttributes()
}
}
+#ifndef QT_NO_WIDGETS
+void tst_QTextTable::columnWidthWithSpans()
+{
+ cleanup();
+ init();
+ QTextTable *table = cursor.insertTable(4, 4);
+ QTextEdit textEdit;
+ textEdit.setDocument(doc);
+ textEdit.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&textEdit));
+
+ for (int i = 0; i < table->columns(); ++i)
+ table->cellAt(0, i).firstCursorPosition().insertText(QString("Header %1").arg(i));
+
+ QTextBlock block = table->cellAt(0, 0).firstCursorPosition().block();
+ const QRectF beforeRect = table->document()->documentLayout()->blockBoundingRect(block);
+ table->mergeCells(1, 0, 1, table->columns());
+ block = table->cellAt(0, 0).firstCursorPosition().block();
+ const QRectF afterRect = table->document()->documentLayout()->blockBoundingRect(block);
+ QCOMPARE(afterRect, beforeRect);
+}
+
+void tst_QTextTable::columnWidthWithImage_data()
+{
+ const auto imageHtml = [](int width, int height) {
+ QImage image(width, height, QImage::Format_RGB32);
+ image.fill(Qt::red);
+ QByteArray imageBytes;
+ QBuffer buffer(&imageBytes);
+ buffer.open(QIODevice::WriteOnly);
+ image.save(&buffer, "png");
+ return QString("<td><img src='data:image/png;base64,%1'/></td>").arg(imageBytes.toBase64());
+ };
+
+ QTest::addColumn<QString>("leftHtml");
+ QTest::addColumn<QString>("rightHtml");
+ QTest::addColumn<QSize>("imageSize");
+ QTest::addRow("image")
+ << imageHtml(500, 32) << "<td></td>" << QSize(500, 32);
+ QTest::addRow("image, text")
+ << imageHtml(32, 32) << "<td>abc</td>" << QSize(32, 32);
+ QTest::addRow("image, 100%% text")
+ << imageHtml(32, 32) << "<td style='background-color: grey' width='100%'>abc</td>"
+ << QSize(32, 32);
+ QTest::addRow("image, image")
+ << imageHtml(256, 32) << imageHtml(256, 32) << QSize(256, 32);
+}
+
+void tst_QTextTable::columnWidthWithImage()
+{
+ const QString tableTemplate = "<table><tr>%1 %2</tr></table>";
+
+ QFETCH(QString, leftHtml);
+ QFETCH(QString, rightHtml);
+ QFETCH(QSize, imageSize);
+
+ QTextDocument doc;
+ doc.setHtml(tableTemplate.arg(leftHtml).arg(rightHtml));
+ QTextEdit textEdit;
+ textEdit.setDocument(&doc);
+ textEdit.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&textEdit));
+
+ QTextCursor cursor(doc.firstBlock());
+ cursor.movePosition(QTextCursor::Right);
+
+ QTextTable *currentTable = cursor.currentTable();
+ QVERIFY(currentTable);
+
+ QTextBlock block = currentTable->cellAt(0, 0).firstCursorPosition().block();
+ const QRectF leftRect = currentTable->document()->documentLayout()->blockBoundingRect(block);
+ block = currentTable->cellAt(0, 1).firstCursorPosition().block();
+ const QRectF rightRect = currentTable->document()->documentLayout()->blockBoundingRect(block);
+ QCOMPARE(leftRect.size().toSize(), imageSize);
+ QVERIFY(rightRect.left() > leftRect.right());
+}
+#endif
+
+
QTEST_MAIN(tst_QTextTable)
#include "tst_qtexttable.moc"
diff --git a/tests/auto/gui/text/qzip/testdata.qrc b/tests/auto/gui/text/qzip/testdata.qrc
deleted file mode 100644
index c7e3a6b14e..0000000000
--- a/tests/auto/gui/text/qzip/testdata.qrc
+++ /dev/null
@@ -1,6 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>testdata/symlink.zip</file>
- <file>testdata/test.zip</file>
- </qresource>
-</RCC>
diff --git a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc b/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
deleted file mode 100644
index c4cef6cc44..0000000000
--- a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
+++ /dev/null
@@ -1,11 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file>texturefiles/car.ktx</file>
- <file>texturefiles/cubemap_float32_rgba.ktx</file>
- <file>texturefiles/cubemap_metadata.ktx</file>
- <file>texturefiles/pattern.pkm</file>
- <file>texturefiles/car_mips.ktx</file>
- <file>texturefiles/newlogo_srgb.astc</file>
- <file>texturefiles/newlogo.astc</file>
- </qresource>
-</RCC>