summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/configure.json54
-rw-r--r--src/gui/doc/qtgui.qdocconf3
-rw-r--r--src/gui/doc/src/external-resources.qdoc10
-rw-r--r--src/gui/doc/src/qtgui.qdoc35
-rw-r--r--src/gui/gui.pro1
-rw-r--r--src/gui/image/qbmphandler.cpp4
-rw-r--r--src/gui/image/qicon.cpp7
-rw-r--r--src/gui/image/qiconloader.cpp14
-rw-r--r--src/gui/image/qiconloader_p.h3
-rw-r--r--src/gui/image/qimage.cpp43
-rw-r--r--src/gui/image/qimage.h7
-rw-r--r--src/gui/image/qimage_conversions.cpp64
-rw-r--r--src/gui/image/qimage_darwin.mm2
-rw-r--r--src/gui/image/qimage_p.h4
-rw-r--r--src/gui/image/qimagereader.cpp11
-rw-r--r--src/gui/image/qimagewriter.cpp10
-rw-r--r--src/gui/image/qimagewriter.h3
-rw-r--r--src/gui/image/qmovie.cpp48
-rw-r--r--src/gui/image/qmovie.h2
-rw-r--r--src/gui/image/qpicture.cpp2
-rw-r--r--src/gui/image/qpicture.h12
-rw-r--r--src/gui/image/qpixmap.cpp71
-rw-r--r--src/gui/image/qpixmap_blitter.cpp7
-rw-r--r--src/gui/image/qplatformpixmap.cpp76
-rw-r--r--src/gui/image/qplatformpixmap.h8
-rw-r--r--src/gui/image/qxpmhandler.cpp5
-rw-r--r--src/gui/kernel/qclipboard.cpp2
-rw-r--r--src/gui/kernel/qcursor.cpp48
-rw-r--r--src/gui/kernel/qcursor.h4
-rw-r--r--src/gui/kernel/qdnd.cpp5
-rw-r--r--src/gui/kernel/qdnd_p.h1
-rw-r--r--src/gui/kernel/qevent.cpp48
-rw-r--r--src/gui/kernel/qevent.h17
-rw-r--r--src/gui/kernel/qguiapplication.cpp171
-rw-r--r--src/gui/kernel/qguiapplication.h2
-rw-r--r--src/gui/kernel/qguiapplication_p.h1
-rw-r--r--src/gui/kernel/qhighdpiscaling.cpp18
-rw-r--r--src/gui/kernel/qkeysequence.cpp20
-rw-r--r--src/gui/kernel/qkeysequence_p.h2
-rw-r--r--src/gui/kernel/qoffscreensurface.cpp20
-rw-r--r--src/gui/kernel/qoffscreensurface.h3
-rw-r--r--src/gui/kernel/qopenglcontext.cpp55
-rw-r--r--src/gui/kernel/qopenglcontext.h7
-rw-r--r--src/gui/kernel/qopenglcontext_p.h2
-rw-r--r--src/gui/kernel/qpalette.cpp40
-rw-r--r--src/gui/kernel/qplatformcursor.cpp41
-rw-r--r--src/gui/kernel/qplatformcursor.h17
-rw-r--r--src/gui/kernel/qplatformdialoghelper.cpp26
-rw-r--r--src/gui/kernel/qplatformdialoghelper.h5
-rw-r--r--src/gui/kernel/qplatformdrag.h1
-rw-r--r--src/gui/kernel/qplatformintegration.cpp31
-rw-r--r--src/gui/kernel/qplatformintegration.h10
-rw-r--r--src/gui/kernel/qplatformmenu.cpp31
-rw-r--r--src/gui/kernel/qplatformmenu.h18
-rw-r--r--src/gui/kernel/qplatformoffscreensurface.h4
-rw-r--r--src/gui/kernel/qplatformsystemtrayicon.cpp11
-rw-r--r--src/gui/kernel/qplatformsystemtrayicon.h2
-rw-r--r--src/gui/kernel/qplatformtheme.cpp6
-rw-r--r--src/gui/kernel/qplatformtheme.h3
-rw-r--r--src/gui/kernel/qplatformwindow.cpp29
-rw-r--r--src/gui/kernel/qplatformwindow.h8
-rw-r--r--src/gui/kernel/qscreen.cpp4
-rw-r--r--src/gui/kernel/qsimpledrag.cpp7
-rw-r--r--src/gui/kernel/qsimpledrag_p.h1
-rw-r--r--src/gui/kernel/qstylehints.cpp11
-rw-r--r--src/gui/kernel/qstylehints.h2
-rw-r--r--src/gui/kernel/qsurface.cpp2
-rw-r--r--src/gui/kernel/qsurface.h1
-rw-r--r--src/gui/kernel/qsurfaceformat.cpp69
-rw-r--r--src/gui/kernel/qsurfaceformat.h9
-rw-r--r--src/gui/kernel/qtouchdevice.cpp9
-rw-r--r--src/gui/kernel/qtouchdevice_p.h1
-rw-r--r--src/gui/kernel/qwindow.cpp334
-rw-r--r--src/gui/kernel/qwindow.h14
-rw-r--r--src/gui/kernel/qwindow_p.h16
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp69
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h35
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h17
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp6
-rw-r--r--src/gui/math3d/qmatrix4x4.h6
-rw-r--r--src/gui/math3d/qquaternion.cpp4
-rw-r--r--src/gui/math3d/qquaternion.h4
-rw-r--r--src/gui/math3d/qvector2d.h2
-rw-r--r--src/gui/math3d/qvector3d.h2
-rw-r--r--src/gui/math3d/qvector4d.h2
-rw-r--r--src/gui/opengl/qopengl.h4
-rw-r--r--src/gui/opengl/qopenglextrafunctions.h496
-rw-r--r--src/gui/opengl/qopenglfunctions.cpp582
-rw-r--r--src/gui/opengl/qopenglgradientcache.cpp3
-rw-r--r--src/gui/opengl/qopengltexture.cpp50
-rw-r--r--src/gui/opengl/qopengltexture.h9
-rw-r--r--src/gui/painting/painting.pri3
-rw-r--r--src/gui/painting/qbackingstore.cpp129
-rw-r--r--src/gui/painting/qbackingstore.h4
-rw-r--r--src/gui/painting/qbrush.cpp2
-rw-r--r--src/gui/painting/qcolor.cpp33
-rw-r--r--src/gui/painting/qcolor.h16
-rw-r--r--src/gui/painting/qcompositionfunctions.cpp792
-rw-r--r--src/gui/painting/qcoregraphics.mm3
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp2
-rw-r--r--src/gui/painting/qdrawhelper.cpp712
-rw-r--r--src/gui/painting/qdrawhelper_avx2.cpp19
-rw-r--r--src/gui/painting/qdrawhelper_p.h4
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp4
-rw-r--r--src/gui/painting/qemulationpaintengine.cpp84
-rw-r--r--src/gui/painting/qgrayraster.c809
-rw-r--r--src/gui/painting/qpagedpaintdevice.cpp12
-rw-r--r--src/gui/painting/qpagedpaintdevice.h2
-rw-r--r--src/gui/painting/qpaintengine.cpp30
-rw-r--r--src/gui/painting/qpaintengine_p.h25
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp13
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h2
-rw-r--r--src/gui/painting/qpainter.cpp12
-rw-r--r--src/gui/painting/qpdf.cpp319
-rw-r--r--src/gui/painting/qpdf.qrc7
-rw-r--r--src/gui/painting/qpdf_p.h11
-rw-r--r--src/gui/painting/qpdfa_metadata.xml16
-rw-r--r--src/gui/painting/qpdfwriter.cpp31
-rw-r--r--src/gui/painting/qpdfwriter.h3
-rw-r--r--src/gui/painting/qplatformbackingstore.cpp77
-rw-r--r--src/gui/painting/qplatformbackingstore.h7
-rw-r--r--src/gui/painting/qpolygon.cpp43
-rw-r--r--src/gui/painting/qpolygon.h4
-rw-r--r--src/gui/text/qdistancefield.cpp12
-rw-r--r--src/gui/text/qfont.cpp5
-rw-r--r--src/gui/text/qfont.h8
-rw-r--r--src/gui/text/qfontengine.cpp4
-rw-r--r--src/gui/text/qfontengine_p.h6
-rw-r--r--src/gui/text/qfontmetrics.cpp2
-rw-r--r--src/gui/text/qfontsubset.cpp8
-rw-r--r--src/gui/text/qstatictext.h2
-rw-r--r--src/gui/text/qtextdocument.cpp2
-rw-r--r--src/gui/text/qtextdocument_p.cpp2
-rw-r--r--src/gui/text/qtextengine.cpp87
-rw-r--r--src/gui/text/qtextengine_p.h17
-rw-r--r--src/gui/text/qtextformat.cpp40
-rw-r--r--src/gui/text/qtexthtmlparser.cpp14
-rw-r--r--src/gui/text/qtexthtmlparser_p.h1
-rw-r--r--src/gui/text/qtextlayout.cpp58
-rw-r--r--src/gui/text/qtextoption.cpp33
-rw-r--r--src/gui/text/qtextoption.h14
-rw-r--r--src/gui/util/qdesktopservices.cpp13
-rw-r--r--src/gui/util/qshaderformat.cpp130
-rw-r--r--src/gui/util/qshaderformat_p.h109
-rw-r--r--src/gui/util/qshadergenerator.cpp351
-rw-r--r--src/gui/util/qshadergenerator_p.h75
-rw-r--r--src/gui/util/qshadergraph.cpp262
-rw-r--r--src/gui/util/qshadergraph_p.h123
-rw-r--r--src/gui/util/qshadergraphloader.cpp254
-rw-r--r--src/gui/util/qshadergraphloader_p.h99
-rw-r--r--src/gui/util/qshaderlanguage.cpp54
-rw-r--r--src/gui/util/qshaderlanguage_p.h163
-rw-r--r--src/gui/util/qshadernode.cpp172
-rw-r--r--src/gui/util/qshadernode_p.h128
-rw-r--r--src/gui/util/qshadernodeport.cpp55
-rw-r--r--src/gui/util/qshadernodeport_p.h88
-rw-r--r--src/gui/util/qshadernodesloader.cpp274
-rw-r--r--src/gui/util/qshadernodesloader_p.h95
-rw-r--r--src/gui/util/qvalidator.cpp12
-rw-r--r--src/gui/util/util.pri20
-rw-r--r--src/gui/vulkan/KHRONOS_LICENSE.txt20
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.cpp88
-rw-r--r--src/gui/vulkan/qplatformvulkaninstance.h91
-rw-r--r--src/gui/vulkan/qt_attribution.json17
-rw-r--r--src/gui/vulkan/qvulkanfunctions.cpp177
-rw-r--r--src/gui/vulkan/qvulkaninstance.cpp894
-rw-r--r--src/gui/vulkan/qvulkaninstance.h202
-rw-r--r--src/gui/vulkan/qvulkanwindow.cpp2720
-rw-r--r--src/gui/vulkan/qvulkanwindow.h165
-rw-r--r--src/gui/vulkan/qvulkanwindow_p.h188
-rw-r--r--src/gui/vulkan/vk.xml5269
-rw-r--r--src/gui/vulkan/vulkan.pri55
172 files changed, 17322 insertions, 1572 deletions
diff --git a/src/gui/configure.json b/src/gui/configure.json
index 1252dc507c..a7f08f2cc0 100644
--- a/src/gui/configure.json
+++ b/src/gui/configure.json
@@ -39,7 +39,9 @@
"qpa-platform-guard": "boolean",
"sm": { "type": "boolean", "name": "sessionmanager" },
"tslib": "boolean",
+ "vulkan": "boolean",
"xcb": { "type": "enum", "values": [ "no", "yes", "qt", "system" ] },
+ "xcb-native-painting": "boolean",
"xcb-xlib": "boolean",
"xinput2": "boolean",
"xkb": "boolean",
@@ -393,6 +395,14 @@
"-lts"
]
},
+ "vulkan": {
+ "label": "Vulkan",
+ "test": "qpa/vulkan",
+ "sources": [
+ { "type": "pkgConfig", "args": "vulkan" },
+ { "type": "makeSpec", "spec": "VULKAN" }
+ ]
+ },
"wayland_server": {
"label": "Wayland Server",
"test": {
@@ -583,6 +593,13 @@
"sources": [
{ "type": "pkgConfig", "args": "xkbcommon xkbcommon-x11 >= 0.4.1" }
]
+ },
+ "xrender": {
+ "label": "XRender for native painting",
+ "test": "x11/xrender",
+ "sources": [
+ "-lXrender"
+ ]
}
},
@@ -826,6 +843,12 @@
},
"use": "opengl_es2"
},
+ "opengles32": {
+ "label": "OpenGL ES 3.2",
+ "type": "compile",
+ "test": "unix/opengles32",
+ "use": "opengl_es2"
+ },
"qpa_default_platform": {
"label": "default QPA platform",
"type": "qpaDefaultPlatform",
@@ -1042,6 +1065,14 @@
{ "type": "define", "name": "QT_OPENGL_ES_3_1" }
]
},
+ "opengles32": {
+ "label": "OpenGL ES 3.2",
+ "condition": "features.opengles31 && tests.opengles32",
+ "output": [
+ "publicFeature",
+ { "type": "define", "name": "QT_OPENGL_ES_3_2" }
+ ]
+ },
"opengl-desktop": {
"label": "Desktop OpenGL",
"enable": "input.opengl == 'desktop'",
@@ -1064,6 +1095,11 @@
"condition": "features.opengl-desktop || features.opengl-dynamic || features.opengles2",
"output": [ "publicFeature", "feature" ]
},
+ "vulkan": {
+ "label": "Vulkan",
+ "condition": "libs.vulkan",
+ "output": [ "publicFeature" ]
+ },
"openvg": {
"label": "OpenVG",
"condition": "libs.openvg",
@@ -1217,6 +1253,18 @@
"condition": "libs.xcb_glx",
"output": [ "privateFeature" ]
},
+ "xcb-native-painting": {
+ "label": "Native painting (experimental)",
+ "emitIf": "features.xcb",
+ "condition": "features.xcb-xlib && features.fontconfig && libs.xrender",
+ "output": [ "privateFeature" ]
+ },
+ "xrender": {
+ "label": "XRender for native painting",
+ "emitIf": "features.xcb && features.xcb-native-painting",
+ "condition": "features.xcb-native-painting",
+ "output": [ "privateFeature" ]
+ },
"xcb-render": {
"label": "XCB render",
"emitIf": "features.xcb",
@@ -1572,9 +1620,11 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
},
"opengles2",
"opengles3",
- "opengles31"
+ "opengles31",
+ "opengles32"
]
},
+ "vulkan",
"sessionmanager"
]
},
@@ -1617,7 +1667,7 @@ QMAKE_LIBDIR_OPENGL[_ES2] and QMAKE_LIBS_OPENGL[_ES2] in the mkspec for your pla
"section": "X11",
"condition": "features.xcb",
"entries": [
- "system-xcb", "egl_x11", "xinput2", "xkb", "xlib", "xcb-render", "xcb-glx", "xcb-xlib", "xkbcommon-system"
+ "system-xcb", "egl_x11", "xinput2", "xkb", "xlib", "xcb-render", "xcb-glx", "xcb-xlib", "xkbcommon-system", "xcb-native-painting"
]
},
{
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf
index bac93af775..e1afa426ed 100644
--- a/src/gui/doc/qtgui.qdocconf
+++ b/src/gui/doc/qtgui.qdocconf
@@ -49,11 +49,14 @@ sourcedirs += .. \
src/includes
exampledirs += ../../../examples/gui \
+ ../../../examples/vulkan \
snippets
imagedirs += images \
../../../examples/gui/doc/images \
../../../doc/src/images \
+manifestmeta.highlighted.names = "QtGui/Analog Clock Window Example"
+
navigation.landingpage = "Qt GUI"
navigation.cppclassespage = "Qt GUI C++ Classes"
diff --git a/src/gui/doc/src/external-resources.qdoc b/src/gui/doc/src/external-resources.qdoc
index 480a4057be..0addbb21cd 100644
--- a/src/gui/doc/src/external-resources.qdoc
+++ b/src/gui/doc/src/external-resources.qdoc
@@ -60,3 +60,13 @@
\externalpage https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout
\title Icon Theme Specification - Directory Layout
*/
+
+/*!
+ \externalpage https://www.khronos.org/vulkan/
+ \title Vulkan
+*/
+
+/*!
+ \externalpage https://www.lunarg.com/vulkan-sdk/
+ \title LunarG Vulkan SDK
+*/
diff --git a/src/gui/doc/src/qtgui.qdoc b/src/gui/doc/src/qtgui.qdoc
index a9fe520d5e..da3d419735 100644
--- a/src/gui/doc/src/qtgui.qdoc
+++ b/src/gui/doc/src/qtgui.qdoc
@@ -35,11 +35,11 @@
applications written with Qt.
The Qt GUI module provides classes for windowing system
- integration, event handling, OpenGL and OpenGL ES integration, 2D
- graphics, imaging, fonts and typography. These classes are used
- internally by Qt's user interface technologies and can also be
- used directly, for instance to write applications using low-level
- OpenGL ES graphics APIs.
+ integration, event handling, OpenGL and OpenGL ES integration,
+ Vulkan integration, 2D graphics, imaging, fonts and typography.
+ These classes are used internally by Qt's user interface technologies
+ and can also be used directly, for instance to write applications using
+ low-level OpenGL ES graphics APIs.
To include the definitions of the module's classes, use the
following directive:
@@ -170,6 +170,31 @@
+ \section1 Vulkan Integration
+
+ Qt 5.10 added support for \l {Vulkan}. This requires
+ the presence of the \l{LunarG Vulkan SDK}.
+
+ On Windows, the SDK sets the environment variable \c {VULKAN_SDK},
+ which will be detected by the \c {configure} script.
+
+ On Android, Vulkan headers were added in API level 24 of the NDK.
+
+ Relevant classes:
+
+ \list
+ \li QVulkanDeviceFunctions
+ \li QVulkanExtension
+ \li QVulkanFunctions
+ \li QVulkanInfoVector
+ \li QVulkanInstance
+ \li QVulkanWindow
+ \li QVulkanWindowRenderer
+ \endlist
+
+ For more information, see the \l{Hello Vulkan Widget Example}
+ and the \l {Hello Vulkan Window Example}.
+
\section1 Qt GUI Prior to Qt 5.0
Prior to Qt 5.0, the Qt GUI module was the monolithic container
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index f7d077e656..f8cec00b82 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -47,6 +47,7 @@ include(math3d/math3d.pri)
include(opengl/opengl.pri)
include(animation/animation.pri)
include(itemmodels/itemmodels.pri)
+include(vulkan/vulkan.pri)
QMAKE_LIBS += $$QMAKE_LIBS_GUI
diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp
index 703c5c0f31..587f375ce7 100644
--- a/src/gui/image/qbmphandler.cpp
+++ b/src/gui/image/qbmphandler.cpp
@@ -49,10 +49,10 @@ QT_BEGIN_NAMESPACE
static void swapPixel01(QImage *image) // 1-bpp: swap 0 and 1 pixels
{
- int i;
+ qsizetype i;
if (image->depth() == 1 && image->colorCount() == 2) {
uint *p = (uint *)image->bits();
- int nbytes = image->byteCount();
+ qsizetype nbytes = static_cast<qsizetype>(image->sizeInBytes());
for (i=0; i<nbytes/4; i++) {
*p = ~*p;
p++;
diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp
index fa4b4e01af..9b2e96d4b0 100644
--- a/src/gui/image/qicon.cpp
+++ b/src/gui/image/qicon.cpp
@@ -1469,8 +1469,13 @@ QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRati
return baseFileName;
int dotIndex = baseFileName.lastIndexOf(QLatin1Char('.'));
- if (dotIndex == -1) /* no dot */
+ if (dotIndex == -1) { /* no dot */
dotIndex = baseFileName.size(); /* append */
+ } else if (dotIndex >= 2 && baseFileName[dotIndex - 1] == QLatin1Char('9')
+ && baseFileName[dotIndex - 2] == QLatin1Char('.')) {
+ // If the file has a .9.* (9-patch image) extension, we must ensure that the @nx goes before it.
+ dotIndex -= 2;
+ }
QString atNxfileName = baseFileName;
atNxfileName.insert(dotIndex, QLatin1String("@2x"));
diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp
index 349e0dfbe3..3cb6f46bd6 100644
--- a/src/gui/image/qiconloader.cpp
+++ b/src/gui/image/qiconloader.cpp
@@ -609,18 +609,18 @@ static int directorySizeDistance(const QIconDirInfo &dir, int iconsize, int icon
return INT_MAX;
}
-QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int scale)
+QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QThemeIconInfo &info, const QSize &size, int scale)
{
int iconsize = qMin(size.width(), size.height());
// Note that m_info.entries are sorted so that png-files
// come first
- const int numEntries = m_info.entries.size();
+ const int numEntries = info.entries.size();
// Search for exact matches first
for (int i = 0; i < numEntries; ++i) {
- QIconLoaderEngineEntry *entry = m_info.entries.at(i);
+ QIconLoaderEngineEntry *entry = info.entries.at(i);
if (directoryMatchesSize(entry->dir, iconsize, scale)) {
return entry;
}
@@ -630,7 +630,7 @@ QIconLoaderEngineEntry *QIconLoaderEngine::entryForSize(const QSize &size, int s
int minimalSize = INT_MAX;
QIconLoaderEngineEntry *closestMatch = 0;
for (int i = 0; i < numEntries; ++i) {
- QIconLoaderEngineEntry *entry = m_info.entries.at(i);
+ QIconLoaderEngineEntry *entry = info.entries.at(i);
int distance = directorySizeDistance(entry->dir, iconsize, scale);
if (distance < minimalSize) {
minimalSize = distance;
@@ -654,7 +654,7 @@ QSize QIconLoaderEngine::actualSize(const QSize &size, QIcon::Mode mode,
ensureLoaded();
- QIconLoaderEngineEntry *entry = entryForSize(size);
+ QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
if (entry) {
const QIconDirInfo &dir = entry->dir;
if (dir.type == QIconDirInfo::Scalable)
@@ -718,7 +718,7 @@ QPixmap QIconLoaderEngine::pixmap(const QSize &size, QIcon::Mode mode,
{
ensureLoaded();
- QIconLoaderEngineEntry *entry = entryForSize(size);
+ QIconLoaderEngineEntry *entry = entryForSize(m_info, size);
if (entry)
return entry->pixmap(size, mode, state);
@@ -767,7 +767,7 @@ void QIconLoaderEngine::virtual_hook(int id, void *data)
QIconEngine::ScaledPixmapArgument &arg = *reinterpret_cast<QIconEngine::ScaledPixmapArgument*>(data);
// QIcon::pixmap() multiplies size by the device pixel ratio.
const int integerScale = qCeil(arg.scale);
- QIconLoaderEngineEntry *entry = entryForSize(arg.size / integerScale, integerScale);
+ QIconLoaderEngineEntry *entry = entryForSize(m_info, arg.size / integerScale, integerScale);
arg.pixmap = entry ? entry->pixmap(arg.size, arg.mode, arg.state) : QPixmap();
}
break;
diff --git a/src/gui/image/qiconloader_p.h b/src/gui/image/qiconloader_p.h
index 5f3a3ef948..9398bca585 100644
--- a/src/gui/image/qiconloader_p.h
+++ b/src/gui/image/qiconloader_p.h
@@ -132,12 +132,13 @@ public:
bool read(QDataStream &in) Q_DECL_OVERRIDE;
bool write(QDataStream &out) const Q_DECL_OVERRIDE;
+ Q_GUI_EXPORT static QIconLoaderEngineEntry *entryForSize(const QThemeIconInfo &info, const QSize &size, int scale = 1);
+
private:
QString key() const Q_DECL_OVERRIDE;
bool hasIcon() const;
void ensureLoaded();
void virtual_hook(int id, void *data) Q_DECL_OVERRIDE;
- QIconLoaderEngineEntry *entryForSize(const QSize &size, int scale = 1);
QIconLoaderEngine(const QIconLoaderEngine &other);
QThemeIconInfo m_info;
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index bd10012bf6..7999ce6bbe 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -127,11 +127,11 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format)
const int bytes_per_line = ((width * depth + 31) >> 5) << 2; // bytes per scanline (must be multiple of 4)
// sanity check for potential overflows
- if (INT_MAX/depth < width
+ if (std::numeric_limits<int>::max()/depth < width
|| bytes_per_line <= 0
|| height <= 0
- || INT_MAX/uint(bytes_per_line) < height
- || INT_MAX/sizeof(uchar *) < uint(height))
+ || std::numeric_limits<qsizetype>::max()/uint(bytes_per_line) < height
+ || std::numeric_limits<int>::max()/sizeof(uchar *) < uint(height))
return 0;
QScopedPointer<QImageData> d(new QImageData);
@@ -452,7 +452,7 @@ bool QImageData::checkForAlphaPixels() const
used. For more information see the
\l {QImage#Image Formats}{Image Formats} section.
- The format(), bytesPerLine(), and byteCount() functions provide
+ The format(), bytesPerLine(), and sizeInBytes() functions provide
low-level information about the data stored in the image.
The cacheKey() function returns a number that uniquely
@@ -1449,26 +1449,43 @@ void QImage::setDevicePixelRatio(qreal scaleFactor)
/*!
\since 4.6
+ \obsolete
Returns the number of bytes occupied by the image data.
- \sa bytesPerLine(), bits(), {QImage#Image Information}{Image
+ Note this method should never be called on an image larger than 2 gigabytes.
+ Instead use sizeInBytes().
+
+ \sa sizeInBytes(), bytesPerLine(), bits(), {QImage#Image Information}{Image
Information}
*/
int QImage::byteCount() const
{
+ Q_ASSERT(!d || d->nbytes < std::numeric_limits<int>::max());
+ return d ? int(d->nbytes) : 0;
+}
+
+/*!
+ \since 5.10
+ Returns the image data size in bytes.
+
+ \sa byteCount(), bytesPerLine(), bits(), {QImage#Image Information}{Image
+ Information}
+*/
+qsizetype QImage::sizeInBytes() const
+{
return d ? d->nbytes : 0;
}
/*!
Returns the number of bytes per image scanline.
- This is equivalent to byteCount() / height().
+ This is equivalent to sizeInBytes() / height() if height() is non-zero.
\sa scanLine()
*/
int QImage::bytesPerLine() const
{
- return (d && d->height) ? d->nbytes / d->height : 0;
+ return d ? d->bytes_per_line : 0;
}
@@ -1595,7 +1612,7 @@ const uchar *QImage::constScanLine(int i) const
data, thus ensuring that this QImage is the only one using the
current return value.
- \sa scanLine(), byteCount(), constBits()
+ \sa scanLine(), sizeInBytes(), constBits()
*/
uchar *QImage::bits()
{
@@ -4662,12 +4679,12 @@ QImage QImage::transformed(const QTransform &matrix, Qt::TransformationMode mode
if (dImage.d->colortable.size() < 256) {
// colors are left in the color table, so pick that one as transparent
dImage.d->colortable.append(0x0);
- memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.byteCount());
+ memset(dImage.bits(), dImage.d->colortable.size() - 1, dImage.d->nbytes);
} else {
- memset(dImage.bits(), 0, dImage.byteCount());
+ memset(dImage.bits(), 0, dImage.d->nbytes);
}
} else
- memset(dImage.bits(), 0x00, dImage.byteCount());
+ memset(dImage.bits(), 0x00, dImage.d->nbytes);
if (target_format >= QImage::Format_RGB32) {
// Prevent QPainter from applying devicePixelRatio corrections
@@ -4772,7 +4789,7 @@ QDebug operator<<(QDebug dbg, const QImage &i)
if (i.colorCount())
dbg << ",colorCount=" << i.colorCount();
dbg << ",devicePixelRatio=" << i.devicePixelRatio()
- << ",bytesPerLine=" << i.bytesPerLine() << ",byteCount=" << i.byteCount();
+ << ",bytesPerLine=" << i.bytesPerLine() << ",sizeInBytes=" << i.sizeInBytes();
}
dbg << ')';
return dbg;
@@ -4794,7 +4811,7 @@ QDebug operator<<(QDebug dbg, const QImage &i)
Returns the number of bytes occupied by the image data.
- \sa byteCount()
+ \sa sizeInBytes()
*/
/*!
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index 225ef3d2e8..8112b8e8fd 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -214,7 +214,10 @@ public:
const uchar *bits() const;
const uchar *constBits() const;
- int byteCount() const;
+#if QT_DEPRECATED_SINCE(5, 10)
+ QT_DEPRECATED_X("Use sizeInBytes") int byteCount() const;
+#endif
+ qsizetype sizeInBytes() const;
uchar *scanLine(int);
const uchar *scanLine(int) const;
@@ -468,7 +471,7 @@ inline void QImage::setNumColors(int n)
inline int QImage::numBytes() const
{
- return byteCount();
+ return int(sizeInBytes());
}
#endif
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 50fad1566c..4eef617336 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -40,6 +40,7 @@
#include <private/qdrawhelper_p.h>
#include <private/qguiapplication_p.h>
#include <private/qcolorprofile_p.h>
+#include <private/qendian_p.h>
#include <private/qsimd_p.h>
#include <private/qimage_p.h>
#include <qendian.h>
@@ -126,8 +127,8 @@ static const uint *QT_FASTCALL convertRGB32FromARGB32PM(uint *buffer, const uint
return buffer;
}
-static const uint *QT_FASTCALL convertRGB32ToARGB32PM(uint *buffer, const uint *src, int count,
- const QVector<QRgb> *, QDitherInfo *)
+static const uint *QT_FASTCALL maskRGB32(uint *buffer, const uint *src, int count,
+ const QVector<QRgb> *, QDitherInfo *)
{
for (int i = 0; i < count; ++i)
buffer[i] = 0xff000000 |src[i];
@@ -160,8 +161,9 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
// If the source doesn't have an alpha channel, we can use the faster convertFromRGB32 method.
convertFromARGB32PM = destLayout->convertFromRGB32;
} else {
+ // The drawhelpers do not mask the alpha value in RGB32, we want to here.
if (src->format == QImage::Format_RGB32)
- convertToARGB32PM = convertRGB32ToARGB32PM;
+ convertToARGB32PM = maskRGB32;
if (dest->format == QImage::Format_RGB32) {
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
if (qCpuHasFeature(SSE4_1))
@@ -171,6 +173,15 @@ void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversio
convertFromARGB32PM = convertRGB32FromARGB32PM;
}
}
+ if ((src->format == QImage::Format_ARGB32 || src->format == QImage::Format_RGBA8888) &&
+ destLayout->alphaWidth == 0 && destLayout->convertFromRGB32) {
+ // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
+ convertToARGB32PM = qPixelLayouts[src->format + 1].convertToARGB32PM;
+ if (dest->format == QImage::Format_RGB32)
+ convertFromARGB32PM = maskRGB32;
+ else
+ convertFromARGB32PM = destLayout->convertFromRGB32;
+ }
QDitherInfo dither;
QDitherInfo *ditherPtr = 0;
if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
@@ -221,7 +232,7 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
convertFromARGB32PM = destLayout->convertFromRGB32;
} else {
if (data->format == QImage::Format_RGB32)
- convertToARGB32PM = convertRGB32ToARGB32PM;
+ convertToARGB32PM = maskRGB32;
if (dst_format == QImage::Format_RGB32) {
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
if (qCpuHasFeature(SSE4_1))
@@ -231,6 +242,15 @@ bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::Im
convertFromARGB32PM = convertRGB32FromARGB32PM;
}
}
+ if ((data->format == QImage::Format_ARGB32 || data->format == QImage::Format_RGBA8888) &&
+ destLayout->alphaWidth == 0 && destLayout->convertFromRGB32) {
+ // Avoid unnecessary premultiply and unpremultiply when converting from unpremultiplied src format.
+ convertToARGB32PM = qPixelLayouts[data->format + 1].convertToARGB32PM;
+ if (dst_format == QImage::Format_RGB32)
+ convertFromARGB32PM = maskRGB32;
+ else
+ convertFromARGB32PM = destLayout->convertFromRGB32;
+ }
QDitherInfo dither;
QDitherInfo *ditherPtr = 0;
if ((flags & Qt::PreferDither) && (flags & Qt::Dither_Mask) != Qt::ThresholdDither)
@@ -322,10 +342,10 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32(quint32 *dest_data, con
// Handle 4 pixels at a time 12 bytes input to 16 bytes output.
for (; pixel + 3 < len; pixel += 4) {
- const quint32 *src_packed = (const quint32 *) src_data;
- const quint32 src1 = qFromBigEndian(src_packed[0]);
- const quint32 src2 = qFromBigEndian(src_packed[1]);
- const quint32 src3 = qFromBigEndian(src_packed[2]);
+ const quint32_be *src_packed = reinterpret_cast<const quint32_be *>(src_data);
+ const quint32 src1 = src_packed[0];
+ const quint32 src2 = src_packed[1];
+ const quint32 src3 = src_packed[2];
dest_data[0] = 0xff000000 | (src1 >> 8);
dest_data[1] = 0xff000000 | (src1 << 16) | (src2 >> 16);
@@ -803,8 +823,8 @@ static bool convert_indexed8_to_ARGB_PM_inplace(QImageData *data, Qt::ImageConve
const int depth = 32;
- const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
- const int nbytes = dst_bytes_per_line * data->height;
+ const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const qsizetype nbytes = dst_bytes_per_line * data->height;
uchar *const newData = (uchar *)realloc(data->data, nbytes);
if (!newData)
return false;
@@ -857,8 +877,8 @@ static bool convert_indexed8_to_ARGB_inplace(QImageData *data, Qt::ImageConversi
const int depth = 32;
- const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
- const int nbytes = dst_bytes_per_line * data->height;
+ const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const qsizetype nbytes = dst_bytes_per_line * data->height;
uchar *const newData = (uchar *)realloc(data->data, nbytes);
if (!newData)
return false;
@@ -925,8 +945,8 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers
const int depth = 16;
- const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
- const int nbytes = dst_bytes_per_line * data->height;
+ const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const qsizetype nbytes = dst_bytes_per_line * data->height;
uchar *const newData = (uchar *)realloc(data->data, nbytes);
if (!newData)
return false;
@@ -982,8 +1002,8 @@ static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFl
const int depth = 16;
- const int dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
- const int src_bytes_per_line = data->bytes_per_line;
+ const qsizetype dst_bytes_per_line = ((data->width * depth + 31) >> 5) << 2;
+ const qsizetype src_bytes_per_line = data->bytes_per_line;
quint32 *src_data = (quint32 *) data->data;
quint16 *dst_data = (quint16 *) data->data;
@@ -1237,9 +1257,9 @@ void dither_to_Mono(QImageData *dst, const QImageData *src,
}
uchar *dst_data = dst->data;
- int dst_bpl = dst->bytes_per_line;
+ qsizetype dst_bpl = dst->bytes_per_line;
const uchar *src_data = src->data;
- int src_bpl = src->bytes_per_line;
+ qsizetype src_bpl = src->bytes_per_line;
switch (dithermode) {
case Diffuse: {
@@ -1892,8 +1912,8 @@ static void convert_Indexed8_to_Alpha8(QImageData *dest, const QImageData *src,
if (simpleCase)
memcpy(dest->data, src->data, src->bytes_per_line * src->height);
else {
- int size = src->bytes_per_line * src->height;
- for (int i = 0; i < size; ++i) {
+ qsizetype size = src->bytes_per_line * src->height;
+ for (qsizetype i = 0; i < size; ++i) {
dest->data[i] = translate[src->data[i]];
}
}
@@ -1916,8 +1936,8 @@ static void convert_Indexed8_to_Grayscale8(QImageData *dest, const QImageData *s
if (simpleCase)
memcpy(dest->data, src->data, src->bytes_per_line * src->height);
else {
- int size = src->bytes_per_line * src->height;
- for (int i = 0; i < size; ++i) {
+ qsizetype size = src->bytes_per_line * src->height;
+ for (qsizetype i = 0; i < size; ++i) {
dest->data[i] = translate[src->data[i]];
}
}
diff --git a/src/gui/image/qimage_darwin.mm b/src/gui/image/qimage_darwin.mm
index 3764bef06b..a5c391ad21 100644
--- a/src/gui/image/qimage_darwin.mm
+++ b/src/gui/image/qimage_darwin.mm
@@ -130,7 +130,7 @@ CGImageRef QImage::toCGImage() const
auto deleter = [](void *image, const void *, size_t)
{ delete static_cast<QImage *>(image); };
QCFType<CGDataProviderRef> dataProvider =
- CGDataProviderCreateWithData(new QImage(*this), bits(), byteCount(), deleter);
+ CGDataProviderCreateWithData(new QImage(*this), bits(), sizeInBytes(), deleter);
QCFType<CGColorSpaceRef> colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index 775ab6d541..befecbfe8b 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -71,12 +71,12 @@ struct Q_GUI_EXPORT QImageData { // internal image data
int width;
int height;
int depth;
- int nbytes; // number of bytes data
+ qsizetype nbytes; // number of bytes data
qreal devicePixelRatio;
QVector<QRgb> colortable;
uchar *data;
QImage::Format format;
- int bytes_per_line;
+ qsizetype bytes_per_line;
int ser_no; // serial number
int detach_no;
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index e1089936c2..7086e102ea 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -570,6 +570,16 @@ bool QImageReaderPrivate::initHandler()
// probe the file extension
if (deleteDevice && !device->isOpen() && !device->open(QIODevice::ReadOnly) && autoDetectImageFormat) {
+ Q_ASSERT(qobject_cast<QFile*>(device) != 0); // future-proofing; for now this should always be the case, so...
+ QFile *file = static_cast<QFile *>(device);
+
+ if (file->error() == QFileDevice::ResourceError) {
+ // this is bad. we should abort the open attempt and note the failure.
+ imageReaderError = QImageReader::DeviceError;
+ errorString = file->errorString();
+ return false;
+ }
+
QList<QByteArray> extensions = QImageReader::supportedImageFormats();
if (!format.isEmpty()) {
// Try the most probable extension first
@@ -580,7 +590,6 @@ bool QImageReaderPrivate::initHandler()
int currentExtension = 0;
- QFile *file = static_cast<QFile *>(device);
QString fileName = file->fileName();
do {
diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp
index ab15d8ee29..a39d204677 100644
--- a/src/gui/image/qimagewriter.cpp
+++ b/src/gui/image/qimagewriter.cpp
@@ -87,6 +87,9 @@
\value UnsupportedFormatError Qt does not support the requested
image format.
+ \value InvalidImageError An attempt was made to write an invalid QImage. An
+ example of an invalid image would be a null QImage.
+
\value UnknownError An unknown error occurred. If you get this
value after calling write(), it is most likely caused by a bug in
QImageWriter.
@@ -736,6 +739,13 @@ extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orie
*/
bool QImageWriter::write(const QImage &image)
{
+ // Do this before canWrite, so it doesn't create a file if this fails.
+ if (Q_UNLIKELY(image.isNull())) {
+ d->imageWriterError = QImageWriter::InvalidImageError;
+ d->errorString = QImageWriter::tr("Image is empty");
+ return false;
+ }
+
if (!canWrite())
return false;
diff --git a/src/gui/image/qimagewriter.h b/src/gui/image/qimagewriter.h
index 58f8c51472..fd1fdd07e8 100644
--- a/src/gui/image/qimagewriter.h
+++ b/src/gui/image/qimagewriter.h
@@ -60,7 +60,8 @@ public:
enum ImageWriterError {
UnknownError,
DeviceError,
- UnsupportedFormatError
+ UnsupportedFormatError,
+ InvalidImageError
};
QImageWriter();
diff --git a/src/gui/image/qmovie.cpp b/src/gui/image/qmovie.cpp
index fbbf6e9802..d5e8b1b974 100644
--- a/src/gui/image/qmovie.cpp
+++ b/src/gui/image/qmovie.cpp
@@ -161,6 +161,8 @@
This signal is emitted by QMovie when the error \a error occurred during
playback. QMovie will stop the movie, and enter QMovie::NotRunning state.
+
+ \sa lastError(), lastErrorString()
*/
/*! \fn void QMovie::finished()
@@ -328,6 +330,8 @@ int QMoviePrivate::speedAdjustedDelay(int delay) const
*/
QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
{
+ Q_Q(QMovie);
+
if (frameNumber < 0)
return QFrameInfo(); // Invalid
@@ -356,7 +360,8 @@ QFrameInfo QMoviePrivate::infoForFrame(int frameNumber)
reader = new QImageReader(device, format);
else
reader = new QImageReader(absoluteFilePath, format);
- (void)reader->canRead(); // Provoke a device->open() call
+ if (!reader->canRead()) // Provoke a device->open() call
+ emit q->error(reader->error());
reader->device()->seek(initialDevicePos);
reader->setBackgroundColor(bgColor);
reader->setScaledSize(scaledSize);
@@ -523,8 +528,20 @@ void QMoviePrivate::_q_loadNextFrame(bool starting)
*/
bool QMoviePrivate::isValid() const
{
- return (greatestFrameNumber >= 0) // have we seen valid data
- || reader->canRead(); // or does the reader see valid data
+ Q_Q(const QMovie);
+
+ if (greatestFrameNumber >= 0)
+ return true; // have we seen valid data
+ bool canRead = reader->canRead();
+ if (!canRead) {
+ // let the consumer know it's broken
+ //
+ // ### the const_cast here is ugly, but 'const' of this method is
+ // technically wrong right now, since it may cause the underlying device
+ // to open.
+ emit const_cast<QMovie*>(q)->error(reader->error());
+ }
+ return canRead;
}
/*!
@@ -775,6 +792,8 @@ QImage QMovie::currentImage() const
/*!
Returns \c true if the movie is valid (e.g., the image data is readable and
the image format is supported); otherwise returns \c false.
+
+ For information about why the movie is not valid, see lastError().
*/
bool QMovie::isValid() const
{
@@ -783,6 +802,29 @@ bool QMovie::isValid() const
}
/*!
+ Returns the most recent error that occurred while attempting to read image data.
+
+ \sa lastErrorString()
+*/
+QImageReader::ImageReaderError QMovie::lastError() const
+{
+ Q_D(const QMovie);
+ return d->reader->error();
+}
+
+/*!
+ Returns a human-readable representation of the most recent error that occurred
+ while attempting to read image data.
+
+ \sa lastError()
+*/
+QString QMovie::lastErrorString() const
+{
+ Q_D(const QMovie);
+ return d->reader->errorString();
+}
+
+/*!
Returns the number of frames in the movie.
Certain animation formats do not support this feature, in which
diff --git a/src/gui/image/qmovie.h b/src/gui/image/qmovie.h
index 930d502892..ca559d491b 100644
--- a/src/gui/image/qmovie.h
+++ b/src/gui/image/qmovie.h
@@ -105,6 +105,8 @@ public:
QPixmap currentPixmap() const;
bool isValid() const;
+ QImageReader::ImageReaderError lastError() const;
+ QString lastErrorString() const;
bool jumpToFrame(int frameNumber);
int loopCount() const;
diff --git a/src/gui/image/qpicture.cpp b/src/gui/image/qpicture.cpp
index 010f5ecf67..bf628e7571 100644
--- a/src/gui/image/qpicture.cpp
+++ b/src/gui/image/qpicture.cpp
@@ -1194,6 +1194,7 @@ QT_BEGIN_INCLUDE_NAMESPACE
#include "qpictureformatplugin.h"
QT_END_INCLUDE_NAMESPACE
+#if QT_DEPRECATED_SINCE(5, 10)
/*!
\obsolete
@@ -1284,6 +1285,7 @@ QList<QByteArray> QPicture::outputFormats()
{
return QPictureIO::outputFormats();
}
+#endif // QT_DEPRECATED_SINCE(5, 10)
/*****************************************************************************
QPictureIO member functions
diff --git a/src/gui/image/qpicture.h b/src/gui/image/qpicture.h
index 8da11caee4..db2b767efe 100644
--- a/src/gui/image/qpicture.h
+++ b/src/gui/image/qpicture.h
@@ -90,11 +90,13 @@ public:
friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &in, const QPicture &p);
friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &in, QPicture &p);
- static const char* pictureFormat(const QString &fileName);
- static QList<QByteArray> inputFormats();
- static QList<QByteArray> outputFormats();
- static QStringList inputFormatList();
- static QStringList outputFormatList();
+#if QT_DEPRECATED_SINCE(5, 10)
+ static QT_DEPRECATED const char* pictureFormat(const QString &fileName);
+ static QT_DEPRECATED QList<QByteArray> inputFormats();
+ static QT_DEPRECATED QList<QByteArray> outputFormats();
+ static QT_DEPRECATED QStringList inputFormatList();
+ static QT_DEPRECATED QStringList outputFormatList();
+#endif // QT_DEPRECATED_SINCE(5, 10)
QPaintEngine *paintEngine() const Q_DECL_OVERRIDE;
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 0aa05a04e2..5b3e3985a7 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -596,44 +596,7 @@ void QPixmap::setMask(const QBitmap &mask)
return;
detach();
-
- QImage image = data->toImage();
- if (mask.size().isEmpty()) {
- if (image.depth() != 1) { // hw: ????
- image = image.convertToFormat(QImage::Format_RGB32);
- }
- } else {
- const int w = image.width();
- const int h = image.height();
-
- switch (image.depth()) {
- case 1: {
- const QImage imageMask = mask.toImage().convertToFormat(image.format());
- for (int y = 0; y < h; ++y) {
- const uchar *mscan = imageMask.scanLine(y);
- uchar *tscan = image.scanLine(y);
- int bytesPerLine = image.bytesPerLine();
- for (int i = 0; i < bytesPerLine; ++i)
- tscan[i] &= mscan[i];
- }
- break;
- }
- default: {
- const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
- image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- for (int y = 0; y < h; ++y) {
- const uchar *mscan = imageMask.scanLine(y);
- QRgb *tscan = (QRgb *)image.scanLine(y);
- for (int x = 0; x < w; ++x) {
- if (!(mscan[x>>3] & (1 << (x&7))))
- tscan[x] = 0;
- }
- }
- break;
- }
- }
- }
- data->fromImage(image, Qt::AutoColor);
+ data->setMask(mask);
}
/*!
@@ -1496,37 +1459,7 @@ QPaintEngine *QPixmap::paintEngine() const
*/
QBitmap QPixmap::mask() const
{
- if (!data || !hasAlphaChannel())
- return QBitmap();
-
- const QImage img = toImage();
- bool shouldConvert = (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied);
- const QImage image = (shouldConvert ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) : img);
- const int w = image.width();
- const int h = image.height();
-
- QImage mask(w, h, QImage::Format_MonoLSB);
- if (mask.isNull()) // allocation failed
- return QBitmap();
-
- mask.setColorCount(2);
- mask.setColor(0, QColor(Qt::color0).rgba());
- mask.setColor(1, QColor(Qt::color1).rgba());
-
- const int bpl = mask.bytesPerLine();
-
- for (int y = 0; y < h; ++y) {
- const QRgb *src = reinterpret_cast<const QRgb*>(image.scanLine(y));
- uchar *dest = mask.scanLine(y);
- memset(dest, 0, bpl);
- for (int x = 0; x < w; ++x) {
- if (qAlpha(*src) > 0)
- dest[x >> 3] |= (1 << (x & 7));
- ++src;
- }
- }
-
- return QBitmap::fromImage(mask);
+ return data ? data->mask() : QBitmap();
}
/*!
diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp
index 950695a9d7..646e737afa 100644
--- a/src/gui/image/qpixmap_blitter.cpp
+++ b/src/gui/image/qpixmap_blitter.cpp
@@ -41,6 +41,7 @@
#include <qpainter.h>
#include <qimage.h>
+#include <qrandom.h>
#include <qscreen.h>
#include <private/qguiapplication_p.h>
@@ -190,8 +191,8 @@ void QBlittablePlatformPixmap::fromImage(const QImage &image,
uchar *mem = thisImg->bits();
const uchar *bits = correctFormatPic.constBits();
- int bytesCopied = 0;
- while (bytesCopied < correctFormatPic.byteCount()) {
+ qsizetype bytesCopied = 0;
+ while (bytesCopied < correctFormatPic.sizeInBytes()) {
memcpy(mem,bits,correctFormatPic.bytesPerLine());
mem += thisImg->bytesPerLine();
bits += correctFormatPic.bytesPerLine();
@@ -252,7 +253,7 @@ QImage *QBlittablePlatformPixmap::overlay()
m_rasterOverlay->size() != QSize(w,h)){
m_rasterOverlay = new QImage(w,h,QImage::Format_ARGB32_Premultiplied);
m_rasterOverlay->fill(0x00000000);
- uint color = (qrand() % 11)+7;
+ uint color = QRandomGenerator::global()->bounded(11)+7;
m_overlayColor = QColor(Qt::GlobalColor(color));
m_overlayColor.setAlpha(0x88);
diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp
index b3b9f79fb1..2209c3de4d 100644
--- a/src/gui/image/qplatformpixmap.cpp
+++ b/src/gui/image/qplatformpixmap.cpp
@@ -163,6 +163,82 @@ bool QPlatformPixmap::scroll(int dx, int dy, const QRect &rect)
return false;
}
+QBitmap QPlatformPixmap::mask() const
+{
+ if (!hasAlphaChannel())
+ return QBitmap();
+
+ const QImage img = toImage();
+ bool shouldConvert = (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied);
+ const QImage image = (shouldConvert ? img.convertToFormat(QImage::Format_ARGB32_Premultiplied) : img);
+ const int w = image.width();
+ const int h = image.height();
+
+ QImage mask(w, h, QImage::Format_MonoLSB);
+ if (mask.isNull()) // allocation failed
+ return QBitmap();
+
+ mask.setColorCount(2);
+ mask.setColor(0, QColor(Qt::color0).rgba());
+ mask.setColor(1, QColor(Qt::color1).rgba());
+
+ const int bpl = mask.bytesPerLine();
+
+ for (int y = 0; y < h; ++y) {
+ const QRgb *src = reinterpret_cast<const QRgb*>(image.scanLine(y));
+ uchar *dest = mask.scanLine(y);
+ memset(dest, 0, bpl);
+ for (int x = 0; x < w; ++x) {
+ if (qAlpha(*src) > 0)
+ dest[x >> 3] |= (1 << (x & 7));
+ ++src;
+ }
+ }
+
+ return QBitmap::fromImage(mask);
+}
+
+void QPlatformPixmap::setMask(const QBitmap &mask)
+{
+ QImage image = toImage();
+ if (mask.size().isEmpty()) {
+ if (image.depth() != 1) { // hw: ????
+ image = image.convertToFormat(QImage::Format_RGB32);
+ }
+ } else {
+ const int w = image.width();
+ const int h = image.height();
+
+ switch (image.depth()) {
+ case 1: {
+ const QImage imageMask = mask.toImage().convertToFormat(image.format());
+ for (int y = 0; y < h; ++y) {
+ const uchar *mscan = imageMask.scanLine(y);
+ uchar *tscan = image.scanLine(y);
+ int bytesPerLine = image.bytesPerLine();
+ for (int i = 0; i < bytesPerLine; ++i)
+ tscan[i] &= mscan[i];
+ }
+ break;
+ }
+ default: {
+ const QImage imageMask = mask.toImage().convertToFormat(QImage::Format_MonoLSB);
+ image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ for (int y = 0; y < h; ++y) {
+ const uchar *mscan = imageMask.scanLine(y);
+ QRgb *tscan = (QRgb *)image.scanLine(y);
+ for (int x = 0; x < w; ++x) {
+ if (!(mscan[x>>3] & (1 << (x&7))))
+ tscan[x] = 0;
+ }
+ }
+ break;
+ }
+ }
+ }
+ fromImage(image, Qt::AutoColor);
+}
+
QPixmap QPlatformPixmap::transformed(const QTransform &matrix,
Qt::TransformationMode mode) const
{
diff --git a/src/gui/image/qplatformpixmap.h b/src/gui/image/qplatformpixmap.h
index 8513755cca..7635ac2949 100644
--- a/src/gui/image/qplatformpixmap.h
+++ b/src/gui/image/qplatformpixmap.h
@@ -69,7 +69,7 @@ public:
enum ClassId { RasterClass, DirectFBClass,
BlitterClass, Direct2DClass,
- CustomClass = 1024 };
+ X11Class, CustomClass = 1024 };
QPlatformPixmap(PixelType pixelType, int classId);
virtual ~QPlatformPixmap();
@@ -99,6 +99,9 @@ public:
virtual int metric(QPaintDevice::PaintDeviceMetric metric) const = 0;
virtual void fill(const QColor &color) = 0;
+ virtual QBitmap mask() const;
+ virtual void setMask(const QBitmap &mask);
+
virtual bool hasAlphaChannel() const = 0;
virtual QPixmap transformed(const QTransform &matrix,
Qt::TransformationMode mode) const;
@@ -144,6 +147,7 @@ protected:
private:
friend class QPixmap;
+ friend class QX11PlatformPixmap;
friend class QImagePixmapCleanupHooks; // Needs to set is_cached
friend class QOpenGLTextureCache; //Needs to check the reference count
friend class QExplicitlySharedDataPointer<QPlatformPixmap>;
@@ -159,7 +163,7 @@ private:
# define QT_XFORM_TYPE_MSBFIRST 0
# define QT_XFORM_TYPE_LSBFIRST 1
-extern bool qt_xForm_helper(const QTransform&, int, int, int, uchar*, int, int, int, const uchar*, int, int, int);
+Q_GUI_EXPORT bool qt_xForm_helper(const QTransform&, int, int, int, uchar*, int, int, int, const uchar*, int, int, int);
QT_END_NAMESPACE
diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp
index ce7f7b8a0f..9c54b9ada4 100644
--- a/src/gui/image/qxpmhandler.cpp
+++ b/src/gui/image/qxpmhandler.cpp
@@ -42,6 +42,7 @@
#ifndef QT_NO_IMAGEFORMAT_XPM
#include <private/qcolor_p.h>
+#include <qbytearraymatcher.h>
#include <qimage.h>
#include <qmap.h>
#include <qtextstream.h>
@@ -1041,7 +1042,9 @@ bool qt_read_xpm_image_or_array(QIODevice *device, const char * const * source,
if ((readBytes = device->readLine(buf.data(), buf.size())) < 0)
return false;
- if (buf.indexOf("/* XPM") != 0) {
+ static Q_RELAXED_CONSTEXPR auto matcher = qMakeStaticByteArrayMatcher("/* XPM");
+
+ if (matcher.indexIn(buf) != 0) {
while (readBytes > 0) {
device->ungetChar(buf.at(readBytes - 1));
--readBytes;
diff --git a/src/gui/kernel/qclipboard.cpp b/src/gui/kernel/qclipboard.cpp
index cd8406b8dc..771f0fe93d 100644
--- a/src/gui/kernel/qclipboard.cpp
+++ b/src/gui/kernel/qclipboard.cpp
@@ -487,7 +487,7 @@ void QClipboard::setMimeData(QMimeData* src, Mode mode)
QPlatformClipboard *clipboard = QGuiApplicationPrivate::platformIntegration()->clipboard();
if (!clipboard->supportsMode(mode)) {
if (src != 0) {
- qWarning("Data set on unsupported clipboard mode. QMimeData object will be deleted.");
+ qDebug("Data set on unsupported clipboard mode. QMimeData object will be deleted.");
src->deleteLater();
}
} else {
diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp
index b7035d47c4..8ae9085d9f 100644
--- a/src/gui/kernel/qcursor.cpp
+++ b/src/gui/kernel/qcursor.cpp
@@ -471,6 +471,54 @@ QCursor::QCursor(Qt::CursorShape shape)
setShape(shape);
}
+/*!
+ \fn bool operator==(const QCursor &lhs, const QCursor &rhs)
+ \relates QCursor
+ \since 5.10
+
+ Equality operator. Returns \c true if \a lhs and \a rhs
+ have the same \l{QCursor::}{shape()} and, in the case of
+ \l{Qt::BitmapCursor}{bitmap cursors}, the same \l{QCursor::}{hotSpot()}
+ and either the same \l{QCursor::}{pixmap()} or the same
+ \l{QCursor::}{bitmap()} and \l{QCursor::}{mask()}.
+
+ \note When comparing bitmap cursors, this function only
+ compares the bitmaps' \l{QPixmap::cacheKey()}{cache keys},
+ not each pixel.
+
+ \sa operator!=(const QCursor &lhs, const QCursor &rhs)
+*/
+bool operator==(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW
+{
+ if (lhs.d == rhs.d)
+ return true; // Copy or same shape
+
+ // Check pixmaps or bitmaps cache keys. Notice that having BitmapCursor
+ // shape implies either non-null pixmap or non-null bitmap and mask
+ if (lhs.shape() == Qt::BitmapCursor && rhs.shape() == Qt::BitmapCursor
+ && lhs.hotSpot() == rhs.hotSpot()) {
+ if (!lhs.d->pixmap.isNull())
+ return lhs.d->pixmap.cacheKey() == rhs.d->pixmap.cacheKey();
+
+ if (!rhs.d->pixmap.isNull())
+ return false;
+
+ return lhs.d->bm->cacheKey() == rhs.d->bm->cacheKey()
+ && lhs.d->bmm->cacheKey() == rhs.d->bmm->cacheKey();
+ }
+
+ return false;
+}
+
+/*!
+ \fn bool operator!=(const QCursor &lhs, const QCursor &rhs)
+ \relates QCursor
+ \since 5.10
+
+ Inequality operator. Returns the equivalent of !(\a lhs == \a rhs).
+
+ \sa operator==(const QCursor &lhs, const QCursor &rhs)
+*/
/*!
Returns the cursor shape identifier. The return value is one of
diff --git a/src/gui/kernel/qcursor.h b/src/gui/kernel/qcursor.h
index c7e9188e5b..ccce3d84ef 100644
--- a/src/gui/kernel/qcursor.h
+++ b/src/gui/kernel/qcursor.h
@@ -112,10 +112,14 @@ public:
inline static void setPos(QScreen *screen, const QPoint &p) { setPos(screen, p.x(), p.y()); }
private:
+ friend Q_GUI_EXPORT bool operator==(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW;
QCursorData *d;
};
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QCursor)
+Q_GUI_EXPORT bool operator==(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW;
+inline bool operator!=(const QCursor &lhs, const QCursor &rhs) Q_DECL_NOTHROW { return !(lhs == rhs); }
+
/*****************************************************************************
QCursor stream functions
*****************************************************************************/
diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp
index a59612474b..3af7f5c181 100644
--- a/src/gui/kernel/qdnd.cpp
+++ b/src/gui/kernel/qdnd.cpp
@@ -71,14 +71,11 @@ QDragManager *QDragManager::m_instance = 0;
QDragManager::QDragManager()
- : QObject(qApp), m_platformDropData(0), m_currentDropTarget(0),
+ : QObject(qApp), m_currentDropTarget(0),
m_platformDrag(QGuiApplicationPrivate::platformIntegration()->drag()),
m_object(0)
{
Q_ASSERT(!m_instance);
-
- if (m_platformDrag)
- m_platformDropData = m_platformDrag->platformDropData();
}
diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h
index 6f2ec46252..eaf6c74fd4 100644
--- a/src/gui/kernel/qdnd_p.h
+++ b/src/gui/kernel/qdnd_p.h
@@ -134,7 +134,6 @@ public:
QObject *source() const;
private:
- QMimeData *m_platformDropData;
QObject *m_currentDropTarget;
QPlatformDrag *m_platformDrag;
QDrag *m_object;
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index c68f9afa56..139b36ef71 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -40,6 +40,7 @@
#include "qevent.h"
#include "qcursor.h"
#include "private/qguiapplication_p.h"
+#include "private/qtouchdevice_p.h"
#include "qpa/qplatformintegration.h"
#include "qpa/qplatformdrag.h"
#include "private/qevent_p.h"
@@ -1526,7 +1527,11 @@ QMoveEvent::~QMoveEvent()
\ingroup events
Expose events are sent to windows when an area of the window is invalidated
- or window visibility in the windowing system changes.
+ or window exposure in the windowing system changes.
+
+ A Window with a client area that is completely covered by another window, or
+ is otherwise not visible may be considered obscured by Qt and may in such
+ cases not receive expose events.
The event handler QWindow::exposeEvent() receives expose events.
*/
@@ -2761,20 +2766,55 @@ Qt::MouseButtons QTabletEvent::buttons() const
*/
/*!
- Constructs a native gesture event of type \a type.
+ \deprecated The QTouchDevice parameter is now required
+*/
+#if QT_DEPRECATED_SINCE(5, 10)
+QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos,
+ const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue)
+ : QInputEvent(QEvent::NativeGesture), mGestureType(type),
+ mLocalPos(localPos), mWindowPos(windowPos), mScreenPos(screenPos), mRealValue(realValue),
+ mSequenceId(sequenceId), mIntValue(intValue)
+{ }
+#endif
+
+typedef QHash<const QNativeGestureEvent*, const QTouchDevice*> NativeGestureEventDataHash;
+// ### Qt6: move this to a member in QNativeGestureEvent
+Q_GLOBAL_STATIC(NativeGestureEventDataHash, g_nativeGestureEventDataHash)
+
+/*!
+ Constructs a native gesture event of type \a type originating from \a device.
The points \a localPos, \a windowPos and \a screenPos specify the
gesture position relative to the receiving widget or item,
window, and screen, respectively.
\a realValue is the \macos event parameter, \a sequenceId and \a intValue are the Windows event parameters.
+ \since 5.10
*/
-QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos,
+QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QTouchDevice *device, const QPointF &localPos, const QPointF &windowPos,
const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue)
: QInputEvent(QEvent::NativeGesture), mGestureType(type),
mLocalPos(localPos), mWindowPos(windowPos), mScreenPos(screenPos), mRealValue(realValue),
mSequenceId(sequenceId), mIntValue(intValue)
-{ }
+{
+ g_nativeGestureEventDataHash->insert(this, device);
+}
+
+QNativeGestureEvent::~QNativeGestureEvent()
+{
+ g_nativeGestureEventDataHash->remove(this);
+}
+
+/*!
+ \since 5.10
+
+ Returns the device.
+*/
+
+const QTouchDevice *QNativeGestureEvent::device() const
+{
+ return g_nativeGestureEventDataHash->value(this);
+}
/*!
\fn QNativeGestureEvent::gestureType() const
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index b8f86acd75..372b5f0896 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -205,10 +205,10 @@ public:
#ifndef QT_NO_INTEGER_EVENT_COORDINATES
inline QPoint pos() const { return p.toPoint(); }
inline QPoint globalPos() const { return g.toPoint(); }
- inline int x() const { return p.x(); }
- inline int y() const { return p.y(); }
- inline int globalX() const { return g.x(); }
- inline int globalY() const { return g.y(); }
+ inline int x() const { return int(p.x()); }
+ inline int y() const { return int(p.y()); }
+ inline int globalX() const { return int(g.x()); }
+ inline int globalY() const { return int(g.y()); }
#endif
inline const QPointF &posF() const { return p; }
inline const QPointF &globalPosF() const { return g; }
@@ -301,8 +301,13 @@ protected:
class Q_GUI_EXPORT QNativeGestureEvent : public QInputEvent
{
public:
- QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos,
+#if QT_DEPRECATED_SINCE(5, 10)
+ QT_DEPRECATED QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos,
const QPointF &screenPos, qreal value, ulong sequenceId, quint64 intArgument);
+#endif
+ QNativeGestureEvent(Qt::NativeGestureType type, const QTouchDevice *dev, const QPointF &localPos, const QPointF &windowPos,
+ const QPointF &screenPos, qreal value, ulong sequenceId, quint64 intArgument);
+ ~QNativeGestureEvent();
Qt::NativeGestureType gestureType() const { return mGestureType; }
qreal value() const { return mRealValue; }
@@ -314,6 +319,8 @@ public:
const QPointF &windowPos() const { return mWindowPos; }
const QPointF &screenPos() const { return mScreenPos; }
+ const QTouchDevice *device() const;
+
protected:
Qt::NativeGestureType mGestureType;
QPointF mLocalPos;
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index cff11367f7..8996e1d7e6 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -164,8 +164,6 @@ QString *QGuiApplicationPrivate::desktopFileName = 0;
QPalette *QGuiApplicationPrivate::app_pal = 0; // default application palette
-Qt::MouseButtons QGuiApplicationPrivate::buttons = Qt::NoButton;
-
ulong QGuiApplicationPrivate::mousePressTime = 0;
Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
int QGuiApplicationPrivate::mousePressX = 0;
@@ -570,6 +568,15 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and
\c none disables them.
\li \c {fontengine=freetype}, uses the FreeType font engine.
+ \li \c {menus=[native|none]}, controls the use of native menus.
+
+ Native menus are implemented using Win32 API and are simpler than
+ QMenu-based menus in for example that they do allow for placing
+ widgets on them or changing properties like fonts and do not
+ provide hover signals. They are mainly intended for Qt Quick.
+ By default, they will be used if the application is not an
+ instance of QApplication or for Qt Quick Controls 2
+ applications.
\endlist
For more information about the platform-specific arguments available for
@@ -981,6 +988,34 @@ QList<QScreen *> QGuiApplication::screens()
}
/*!
+ Returns the screen at \a point, or \c nullptr if outside of any screen.
+
+ The \a point is in relation to the virtualGeometry() of each set of virtual
+ siblings. If the point maps to more than one set of virtual siblings the first
+ match is returned.
+
+ \since 5.10
+*/
+QScreen *QGuiApplication::screenAt(const QPoint &point)
+{
+ QVarLengthArray<const QScreen *, 8> visitedScreens;
+ for (const QScreen *screen : QGuiApplication::screens()) {
+ if (visitedScreens.contains(screen))
+ continue;
+
+ // The virtual siblings include the screen itself, so iterate directly
+ for (QScreen *sibling : screen->virtualSiblings()) {
+ if (sibling->geometry().contains(point))
+ return sibling;
+
+ visitedScreens.append(sibling);
+ }
+ }
+
+ return nullptr;
+}
+
+/*!
\fn void QGuiApplication::screenAdded(QScreen *screen)
This signal is emitted whenever a new screen \a screen has been added to the system.
@@ -1043,38 +1078,11 @@ qreal QGuiApplication::devicePixelRatio() const
*/
QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
{
- const QList<QScreen *> screens = QGuiApplication::screens();
- if (!screens.isEmpty()) {
- const QList<QScreen *> primaryScreens = screens.first()->virtualSiblings();
- QScreen *windowScreen = Q_NULLPTR;
-
- // Find the window on the primary virtual desktop first
- for (QScreen *screen : primaryScreens) {
- if (screen->geometry().contains(pos)) {
- windowScreen = screen;
- break;
- }
- }
-
- // If the window is not found on primary virtual desktop, find it on all screens
- // except the first which was for sure in the previous loop. Some other screens
- // may repeat. Find only when there is more than one virtual desktop.
- if (!windowScreen && screens.count() != primaryScreens.count()) {
- for (int i = 1; i < screens.size(); ++i) {
- QScreen *screen = screens.at(i);
- if (screen->geometry().contains(pos)) {
- windowScreen = screen;
- break;
- }
- }
- }
-
- if (windowScreen) {
- const QPoint devicePosition = QHighDpi::toNativePixels(pos, windowScreen);
- return windowScreen->handle()->topLevelAt(devicePosition);
- }
+ if (QScreen *windowScreen = screenAt(pos)) {
+ const QPoint devicePosition = QHighDpi::toNativePixels(pos, windowScreen);
+ return windowScreen->handle()->topLevelAt(devicePosition);
}
- return Q_NULLPTR;
+ return nullptr;
}
/*!
@@ -1841,7 +1849,7 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e)
{
QEvent::Type type;
- Qt::MouseButtons stateChange = e->buttons ^ buttons;
+ Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons;
if (e->globalPos != QGuiApplicationPrivate::lastCursorPosition && (stateChange != Qt::NoButton)) {
// A mouse event should not change both position and buttons at the same time. Instead we
// should first send a move event followed by a button changed event. Since this is not the case
@@ -1850,7 +1858,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
e->window.data(), e->timestamp, e->type, e->localPos, e->globalPos, e->buttons, e->modifiers, e->source);
if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic)
mouseButtonEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
- e->buttons = buttons;
+ e->buttons = mouse_buttons;
processMouseEvent(e);
processMouseEvent(&mouseButtonEvent);
return;
@@ -1904,7 +1912,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
// Ignore mouse events that don't change the current state.
return;
}
- mouse_buttons = buttons = e->buttons;
+ mouse_buttons = e->buttons;
if (button & e->buttons) {
ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
@@ -1929,14 +1937,14 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen);
const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
- button, buttons, e->modifiers, e->source);
+ button, mouse_buttons, e->modifiers, e->source);
ev.setTimestamp(e->timestamp);
cursor->pointerEvent(ev);
}
}
#endif
- QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers, e->source);
+ QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, mouse_buttons, e->modifiers, e->source);
ev.setTimestamp(e->timestamp);
if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
@@ -1970,7 +1978,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
point.state = Qt::TouchPointPressed;
} else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) {
point.state = Qt::TouchPointReleased;
- } else if (type == QEvent::MouseMove && (buttons & Qt::LeftButton)) {
+ } else if (type == QEvent::MouseMove && (mouse_buttons & Qt::LeftButton)) {
point.state = Qt::TouchPointMoved;
} else {
return;
@@ -1991,7 +1999,7 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press
const QEvent::Type doubleClickType = frameStrut ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
- button, buttons, e->modifiers, e->source);
+ button, mouse_buttons, e->modifiers, e->source);
dblClickEvent.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
}
@@ -2025,7 +2033,7 @@ void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wh
}
QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation,
- buttons, e->modifiers, e->phase, e->source, e->inverted);
+ mouse_buttons, e->modifiers, e->phase, e->source, e->inverted);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(window, &ev);
#else
@@ -2209,7 +2217,7 @@ void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterf
}
// we may have changed scaling, so trigger resize event if needed
if (window->handle()) {
- QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window), QRect());
+ QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window));
processGeometryChangeEvent(&gce);
}
}
@@ -2245,35 +2253,46 @@ void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePr
if (!window)
return;
- QRect newRect = e->newGeometry;
- QRect oldRect = e->oldGeometry.isNull() ? window->d_func()->geometry : e->oldGeometry;
-
- bool isResize = oldRect.size() != newRect.size();
- bool isMove = oldRect.topLeft() != newRect.topLeft();
-
- window->d_func()->geometry = newRect;
+ const QRect lastReportedGeometry = window->d_func()->geometry;
+ const QRect requestedGeometry = e->requestedGeometry;
+ const QRect actualGeometry = e->newGeometry;
+
+ // We send size and move events only if the geometry has changed from
+ // what was last reported, or if the user tried to set a new geometry,
+ // but the window manager responded by keeping the old geometry. In the
+ // latter case we send move/resize events with the same geometry as the
+ // last reported geometry, to indicate that the window wasn't moved or
+ // resized. Note that this logic does not apply to the property changes
+ // of the window, as we don't treat them as part of this request/response
+ // protocol of QWindow/QPA.
+ const bool isResize = actualGeometry.size() != lastReportedGeometry.size()
+ || requestedGeometry.size() != actualGeometry.size();
+ const bool isMove = actualGeometry.topLeft() != lastReportedGeometry.topLeft()
+ || requestedGeometry.topLeft() != actualGeometry.topLeft();
+
+ window->d_func()->geometry = actualGeometry;
if (isResize || window->d_func()->resizeEventPending) {
- QResizeEvent e(newRect.size(), oldRect.size());
+ QResizeEvent e(actualGeometry.size(), lastReportedGeometry.size());
QGuiApplication::sendSpontaneousEvent(window, &e);
window->d_func()->resizeEventPending = false;
- if (oldRect.width() != newRect.width())
- window->widthChanged(newRect.width());
- if (oldRect.height() != newRect.height())
- window->heightChanged(newRect.height());
+ if (actualGeometry.width() != lastReportedGeometry.width())
+ window->widthChanged(actualGeometry.width());
+ if (actualGeometry.height() != lastReportedGeometry.height())
+ window->heightChanged(actualGeometry.height());
}
if (isMove) {
//### frame geometry
- QMoveEvent e(newRect.topLeft(), oldRect.topLeft());
+ QMoveEvent e(actualGeometry.topLeft(), lastReportedGeometry.topLeft());
QGuiApplication::sendSpontaneousEvent(window, &e);
- if (oldRect.x() != newRect.x())
- window->xChanged(newRect.x());
- if (oldRect.y() != newRect.y())
- window->yChanged(newRect.y());
+ if (actualGeometry.x() != lastReportedGeometry.x())
+ window->xChanged(actualGeometry.x());
+ if (actualGeometry.y() != lastReportedGeometry.y())
+ window->yChanged(actualGeometry.y());
}
}
@@ -2415,7 +2434,7 @@ void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate::
if (e->window.isNull())
return;
- QNativeGestureEvent ev(e->type, e->pos, e->pos, e->globalPos, e->realValue, e->sequenceId, e->intValue);
+ QNativeGestureEvent ev(e->type, e->device, e->pos, e->pos, e->globalPos, e->realValue, e->sequenceId, e->intValue);
ev.setTimestamp(e->timestamp);
QGuiApplication::sendSpontaneousEvent(e->window, &ev);
}
@@ -2493,7 +2512,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
e->timestamp,
synthIt->pos,
synthIt->screenPos,
- buttons & ~Qt::LeftButton,
+ mouse_buttons & ~Qt::LeftButton,
e->modifiers,
Qt::MouseEventSynthesizedByQt);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
@@ -2708,7 +2727,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp,
touchPoint.pos(),
touchPoint.screenPos(),
- b | (buttons & ~Qt::LeftButton),
+ b | (mouse_buttons & ~Qt::LeftButton),
e->modifiers,
Qt::MouseEventSynthesizedByQt);
fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
@@ -3548,6 +3567,22 @@ static inline void applyCursor(const QList<QWindow *> &l, const QCursor &c)
}
}
+static inline void applyOverrideCursor(const QList<QScreen *> &screens, const QCursor &c)
+{
+ for (QScreen *screen : screens) {
+ if (QPlatformCursor *cursor = screen->handle()->cursor())
+ cursor->setOverrideCursor(c);
+ }
+}
+
+static inline void clearOverrideCursor(const QList<QScreen *> &screens)
+{
+ for (QScreen *screen : screens) {
+ if (QPlatformCursor *cursor = screen->handle()->cursor())
+ cursor->clearOverrideCursor();
+ }
+}
+
static inline void applyWindowCursor(const QList<QWindow *> &l)
{
for (int i = 0; i < l.size(); ++i) {
@@ -3592,7 +3627,10 @@ void QGuiApplication::setOverrideCursor(const QCursor &cursor)
{
CHECK_QAPP_INSTANCE()
qGuiApp->d_func()->cursor_list.prepend(cursor);
- applyCursor(QGuiApplicationPrivate::window_list, cursor);
+ if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
+ applyOverrideCursor(QGuiApplicationPrivate::screen_list, cursor);
+ else
+ applyCursor(QGuiApplicationPrivate::window_list, cursor);
}
/*!
@@ -3614,8 +3652,13 @@ void QGuiApplication::restoreOverrideCursor()
qGuiApp->d_func()->cursor_list.removeFirst();
if (qGuiApp->d_func()->cursor_list.size() > 0) {
QCursor c(qGuiApp->d_func()->cursor_list.value(0));
- applyCursor(QGuiApplicationPrivate::window_list, c);
+ if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
+ applyOverrideCursor(QGuiApplicationPrivate::screen_list, c);
+ else
+ applyCursor(QGuiApplicationPrivate::window_list, c);
} else {
+ if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
+ clearOverrideCursor(QGuiApplicationPrivate::screen_list);
applyWindowCursor(QGuiApplicationPrivate::window_list);
}
}
diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h
index 6721970222..e130553b9d 100644
--- a/src/gui/kernel/qguiapplication.h
+++ b/src/gui/kernel/qguiapplication.h
@@ -110,6 +110,8 @@ public:
static QScreen *primaryScreen();
static QList<QScreen *> screens();
+ static QScreen *screenAt(const QPoint &point);
+
qreal devicePixelRatio() const;
#ifndef QT_NO_CURSOR
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index d67ab61ff8..becaa7ceb3 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -203,7 +203,6 @@ public:
virtual bool isWindowBlocked(QWindow *window, QWindow **blockingWindow = 0) const;
virtual bool popupActive() { return false; }
- static Qt::MouseButtons buttons;
static ulong mousePressTime;
static Qt::MouseButton mousePressButton;
static int mousePressX;
diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp
index 085652879c..078f185d08 100644
--- a/src/gui/kernel/qhighdpiscaling.cpp
+++ b/src/gui/kernel/qhighdpiscaling.cpp
@@ -376,8 +376,22 @@ qreal QHighDpiScaling::screenSubfactor(const QPlatformScreen *screen)
{
qreal factor = qreal(1.0);
if (screen) {
- if (m_usePixelDensity)
- factor *= screen->pixelDensity();
+ if (m_usePixelDensity) {
+ qreal pixelDensity = screen->pixelDensity();
+
+ // Pixel density reported by the screen is sometimes not precise enough,
+ // so recalculate it: divide px (physical pixels) by dp (device-independent pixels)
+ // for both width and height, and then use the average if it is different from
+ // the one initially reported by the screen
+ QRect screenGeometry = screen->geometry();
+ qreal wFactor = qreal(screenGeometry.width()) / qRound(screenGeometry.width() / pixelDensity);
+ qreal hFactor = qreal(screenGeometry.height()) / qRound(screenGeometry.height() / pixelDensity);
+ qreal averageDensity = (wFactor + hFactor) / 2;
+ if (!qFuzzyCompare(pixelDensity, averageDensity))
+ pixelDensity = averageDensity;
+
+ factor *= pixelDensity;
+ }
if (m_screenFactorSet) {
QVariant screenFactor = screen->screen()->property(scaleFactorProperty);
if (screenFactor.isValid())
diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp
index 01a308372e..71ecc46cb6 100644
--- a/src/gui/kernel/qkeysequence.cpp
+++ b/src/gui/kernel/qkeysequence.cpp
@@ -56,7 +56,6 @@
#if defined(Q_OS_MACX)
#include <QtCore/private/qcore_mac_p.h>
-#include <Carbon/Carbon.h>
#endif
#include <algorithm>
@@ -70,6 +69,13 @@ struct MacSpecialKey {
ushort macSymbol;
};
+// Unicode code points for the glyphs associated with these keys
+// Defined by Carbon headers but not anywhere in Cocoa
+static const int kShiftUnicode = 0x21E7;
+static const int kControlUnicode = 0x2303;
+static const int kOptionUnicode = 0x2325;
+static const int kCommandUnicode = 0x2318;
+
static const int NumEntries = 21;
static const MacSpecialKey entries[NumEntries] = {
{ Qt::Key_Escape, 0x238B },
@@ -244,7 +250,7 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni
corresponds to the \uicontrol Control keys.
\table
- \header \li StandardKey \li Windows \li \macos \li KDE \li GNOME
+ \header \li StandardKey \li Windows \li \macos \li KDE Plasma \li GNOME
\row \li HelpContents \li F1 \li Ctrl+? \li F1 \li F1
\row \li WhatsThis \li Shift+F1 \li Shift+F1 \li Shift+F1 \li Shift+F1
\row \li Open \li Ctrl+O \li Ctrl+O \li Ctrl+O \li Ctrl+O
@@ -1002,7 +1008,6 @@ int QKeySequence::assign(const QString &ks)
int QKeySequence::assign(const QString &ks, QKeySequence::SequenceFormat format)
{
QString keyseq = ks;
- QString part;
int n = 0;
int p = 0, diff = 0;
@@ -1027,9 +1032,9 @@ int QKeySequence::assign(const QString &ks, QKeySequence::SequenceFormat format)
}
}
}
- part = keyseq.left(-1 == p ? keyseq.length() : p - diff);
+ QString part = keyseq.left(-1 == p ? keyseq.length() : p - diff);
keyseq = keyseq.right(-1 == p ? 0 : keyseq.length() - (p + 1));
- d->key[n] = QKeySequencePrivate::decodeString(part, format);
+ d->key[n] = QKeySequencePrivate::decodeString(std::move(part), format);
++n;
}
return n;
@@ -1055,10 +1060,10 @@ int QKeySequence::decodeString(const QString &str)
return QKeySequencePrivate::decodeString(str, NativeText);
}
-int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::SequenceFormat format)
+int QKeySequencePrivate::decodeString(QString accel, QKeySequence::SequenceFormat format)
{
int ret = 0;
- QString accel = str.toLower();
+ accel = std::move(accel).toLower();
bool nativeText = (format == QKeySequence::NativeText);
QVector<QModifKeyName> *gmodifs;
@@ -1094,7 +1099,6 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence
<< QModifKeyName(Qt::KeypadModifier, QLatin1String("num+"));
}
}
- if (!gmodifs) return ret;
QVector<QModifKeyName> modifs;
diff --git a/src/gui/kernel/qkeysequence_p.h b/src/gui/kernel/qkeysequence_p.h
index 8ba86c31b8..fbcab5d34e 100644
--- a/src/gui/kernel/qkeysequence_p.h
+++ b/src/gui/kernel/qkeysequence_p.h
@@ -85,7 +85,7 @@ public:
static QString encodeString(int key, QKeySequence::SequenceFormat format);
// used in dbusmenu
Q_GUI_EXPORT static QString keyName(int key, QKeySequence::SequenceFormat format);
- static int decodeString(const QString &keyStr, QKeySequence::SequenceFormat format);
+ static int decodeString(QString accel, QKeySequence::SequenceFormat format);
};
#endif // QT_NO_SHORTCUT
diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp
index 4d79db8ab2..ae027af627 100644
--- a/src/gui/kernel/qoffscreensurface.cpp
+++ b/src/gui/kernel/qoffscreensurface.cpp
@@ -121,14 +121,16 @@ public:
/*!
- Creates an offscreen surface for the \a targetScreen.
+ \since 5.10
+
+ Creates an offscreen surface for the \a targetScreen with the given \a parent.
The underlying platform surface is not created until create() is called.
\sa setScreen(), create()
*/
-QOffscreenSurface::QOffscreenSurface(QScreen *targetScreen)
- : QObject(*new QOffscreenSurfacePrivate(), 0)
+QOffscreenSurface::QOffscreenSurface(QScreen *targetScreen, QObject *parent)
+ : QObject(*new QOffscreenSurfacePrivate(), parent)
, QSurface(Offscreen)
{
Q_D(QOffscreenSurface);
@@ -143,6 +145,18 @@ QOffscreenSurface::QOffscreenSurface(QScreen *targetScreen)
connect(d->screen, SIGNAL(destroyed(QObject*)), this, SLOT(screenDestroyed(QObject*)));
}
+/*!
+ Creates an offscreen surface for the \a targetScreen.
+
+ The underlying platform surface is not created until create() is called.
+
+ \sa setScreen(), create()
+*/
+QOffscreenSurface::QOffscreenSurface(QScreen *targetScreen)
+ : QOffscreenSurface(targetScreen, nullptr)
+{
+}
+
/*!
Destroys the offscreen surface.
diff --git a/src/gui/kernel/qoffscreensurface.h b/src/gui/kernel/qoffscreensurface.h
index 35c498c89a..3295ae0d40 100644
--- a/src/gui/kernel/qoffscreensurface.h
+++ b/src/gui/kernel/qoffscreensurface.h
@@ -57,7 +57,8 @@ class Q_GUI_EXPORT QOffscreenSurface : public QObject, public QSurface
Q_DECLARE_PRIVATE(QOffscreenSurface)
public:
-
+ // ### Qt 6: merge overloads
+ explicit QOffscreenSurface(QScreen *screen, QObject *parent);
explicit QOffscreenSurface(QScreen *screen = Q_NULLPTR);
virtual ~QOffscreenSurface();
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index ad5e0b518d..27ea3864b9 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -1679,6 +1679,61 @@ void QOpenGLMultiGroupSharedResource::cleanup(QOpenGLContextGroup *group, QOpenG
m_groups.removeOne(group);
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QOpenGLVersionProfile &vp)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QOpenGLVersionProfile(";
+ if (vp.isValid()) {
+ debug << vp.version().first << '.' << vp.version().second
+ << ", profile=" << vp.profile();
+ } else {
+ debug << "invalid";
+ }
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const QOpenGLContext *ctx)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug.noquote();
+ debug << "QOpenGLContext(";
+ if (ctx) {
+ debug << static_cast<const void *>(ctx);
+ if (ctx->isValid()) {
+ debug << ", nativeHandle=" << ctx->nativeHandle()
+ << ", format=" << ctx->format();
+ if (const QSurface *sf = ctx->surface())
+ debug << ", surface=" << sf;
+ if (const QScreen *s = ctx->screen())
+ debug << ", screen=\"" << s->name() << '"';
+ } else {
+ debug << ", invalid";
+ }
+ } else {
+ debug << '0';
+ }
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const QOpenGLContextGroup *cg)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QOpenGLContextGroup(";
+ if (cg)
+ debug << cg->shares();
+ else
+ debug << '0';
+ debug << ')';
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
#include "moc_qopenglcontext.cpp"
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qopenglcontext.h b/src/gui/kernel/qopenglcontext.h
index 3ec9ce3188..07153db84e 100644
--- a/src/gui/kernel/qopenglcontext.h
+++ b/src/gui/kernel/qopenglcontext.h
@@ -69,6 +69,7 @@
QT_BEGIN_NAMESPACE
+class QDebug;
class QOpenGLContextPrivate;
class QOpenGLContextGroupPrivate;
class QOpenGLFunctions;
@@ -249,6 +250,12 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_screenDestroyed(QObject *object))
};
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLVersionProfile &vp);
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLContext *ctx);
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLContextGroup *cg);
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
#endif // QT_NO_OPENGL
diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h
index 64bf55beee..9f9b4352fc 100644
--- a/src/gui/kernel/qopenglcontext_p.h
+++ b/src/gui/kernel/qopenglcontext_p.h
@@ -55,7 +55,7 @@
#ifndef QT_NO_OPENGL
-#include "qopengl.h"
+#include <qopengl.h>
#include "qopenglcontext.h"
#include <private/qobject_p.h>
#include <qmutex.h>
diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp
index a992793246..4905e51e01 100644
--- a/src/gui/kernel/qpalette.cpp
+++ b/src/gui/kernel/qpalette.cpp
@@ -388,7 +388,7 @@ static void qt_palette_from_color(QPalette &pal, const QColor &button)
\warning Some styles do not use the palette for all drawing, for
instance, if they make use of native theme engines. This is the
- case for both the Windows XP, Windows Vista, and the \macos
+ case for both the Windows Vista and the \macos
styles.
\sa QApplication::setPalette(), QWidget::setPalette(), QColor
@@ -751,21 +751,24 @@ const QBrush &QPalette::brush(ColorGroup gr, ColorRole cr) const
void QPalette::setBrush(ColorGroup cg, ColorRole cr, const QBrush &b)
{
Q_ASSERT(cr < NColorRoles);
- detach();
- if(cg >= (int)NColorGroups) {
- if(cg == All) {
- for(int i = 0; i < (int)NColorGroups; i++)
- d->br[i][cr] = b;
- data.resolve_mask |= (1<<cr);
- return;
- } else if(cg == Current) {
- cg = (ColorGroup)data.current_group;
- } else {
- qWarning("QPalette::setBrush: Unknown ColorGroup: %d", (int)cg);
- cg = Active;
- }
+
+ if (cg == All) {
+ for (uint i = 0; i < NColorGroups; i++)
+ setBrush(ColorGroup(i), cr, b);
+ return;
+ }
+
+ if (cg == Current) {
+ cg = ColorGroup(data.current_group);
+ } else if (cg >= NColorGroups) {
+ qWarning("QPalette::setBrush: Unknown ColorGroup: %d", cg);
+ cg = Active;
+ }
+
+ if (d->br[cg][cr] != b) {
+ detach();
+ d->br[cg][cr] = b;
}
- d->br[cg][cr] = b;
data.resolve_mask |= (1<<cr);
}
@@ -1091,7 +1094,6 @@ void QPalette::setColorGroup(ColorGroup cg, const QBrush &foreground, const QBru
const QBrush &link, const QBrush &link_visited,
const QBrush &toolTipBase, const QBrush &toolTipText)
{
- detach();
setBrush(cg, WindowText, foreground);
setBrush(cg, Button, button);
setBrush(cg, Light, light);
@@ -1115,14 +1117,14 @@ void QPalette::setColorGroup(ColorGroup cg, const QBrush &foreground, const QBru
Q_GUI_EXPORT QPalette qt_fusionPalette()
{
- QColor backGround(239, 235, 231);
+ QColor backGround(239, 239, 239);
QColor light = backGround.lighter(150);
QColor mid(backGround.darker(130));
QColor midLight = mid.lighter(110);
QColor base = Qt::white;
QColor disabledBase(backGround);
QColor dark = backGround.darker(150);
- QColor darkDisabled = QColor(209, 200, 191).darker(110);
+ QColor darkDisabled = QColor(209, 209, 209).darker(110);
QColor text = Qt::black;
QColor hightlightedText = Qt::white;
QColor disabledText = QColor(190, 190, 190);
@@ -1145,7 +1147,7 @@ Q_GUI_EXPORT QPalette qt_fusionPalette()
fusionPalette.setBrush(QPalette::Active, QPalette::Highlight, QColor(48, 140, 198));
fusionPalette.setBrush(QPalette::Inactive, QPalette::Highlight, QColor(48, 140, 198));
- fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, QColor(145, 141, 126));
+ fusionPalette.setBrush(QPalette::Disabled, QPalette::Highlight, QColor(145, 145, 145));
return fusionPalette;
}
diff --git a/src/gui/kernel/qplatformcursor.cpp b/src/gui/kernel/qplatformcursor.cpp
index af0214e016..e6cf6a8216 100644
--- a/src/gui/kernel/qplatformcursor.cpp
+++ b/src/gui/kernel/qplatformcursor.cpp
@@ -95,6 +95,17 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QPlatformCursor::Capability
+ \since 5.10
+
+ \value OverrideCursor Indicates that the platform implements
+ QPlatformCursor::setOverrideCursor() and
+ QPlatformCursor::clearOverrideCursor().
+*/
+
+QPlatformCursor::Capabilities QPlatformCursor::m_capabilities = 0;
+
+/*!
\fn QPlatformCursor::QPlatformCursor()
Constructs a QPlatformCursor.
@@ -659,4 +670,34 @@ void QPlatformCursorImage::set(const uchar *data, const uchar *mask,
\brief Return the cursor's hotspot
*/
+#ifndef QT_NO_CURSOR
+/*!
+ Reimplement this function in subclass to set an override cursor
+ on the associated screen and return true to indicate success.
+
+ This function can be implemented on platforms where the cursor is a
+ property of the application or the screen rather than a property
+ of the window. On these platforms, the OverrideCursor capability
+ should be set.
+
+ \sa QGuiApplication::setOverrideCursor(), Capabilities
+
+ \since 5.10
+*/
+void QPlatformCursor::setOverrideCursor(const QCursor &)
+{
+}
+
+/*!
+ Reimplement this function in subclass to clear the override cursor.
+
+ \sa QGuiApplication::clearOverrideCursor(), Capabilities
+
+ \since 5.10
+*/
+void QPlatformCursor::clearOverrideCursor()
+{
+}
+#endif // QT_NO_CURSOR
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformcursor.h b/src/gui/kernel/qplatformcursor.h
index dddd9e5831..40e8a562f8 100644
--- a/src/gui/kernel/qplatformcursor.h
+++ b/src/gui/kernel/qplatformcursor.h
@@ -78,21 +78,36 @@ private:
class Q_GUI_EXPORT QPlatformCursor : public QObject {
public:
+ enum Capability {
+ OverrideCursor = 0x1
+ };
+ Q_DECLARE_FLAGS(Capabilities, Capability)
+
QPlatformCursor();
// input methods
virtual void pointerEvent(const QMouseEvent & event) { Q_UNUSED(event); }
#ifndef QT_NO_CURSOR
virtual void changeCursor(QCursor * windowCursor, QWindow * window) = 0;
-#endif
+ virtual void setOverrideCursor(const QCursor &);
+ virtual void clearOverrideCursor();
+#endif // QT_NO_CURSOR
virtual QPoint pos() const;
virtual void setPos(const QPoint &pos);
+ static Capabilities capabilities() { return m_capabilities; }
+ static void setCapabilities(Capabilities c) { m_capabilities = c; }
+ static void setCapability(Capability c) { m_capabilities.setFlag(c); }
+
private:
friend void qt_qpa_set_cursor(QWidget * w, bool force);
friend class QApplicationPrivate;
+
+ static Capabilities m_capabilities;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformCursor::Capabilities)
+
QT_END_NAMESPACE
#endif // QPLATFORMCURSOR_H
diff --git a/src/gui/kernel/qplatformdialoghelper.cpp b/src/gui/kernel/qplatformdialoghelper.cpp
index 01cf98c7c9..ad134ebe7f 100644
--- a/src/gui/kernel/qplatformdialoghelper.cpp
+++ b/src/gui/kernel/qplatformdialoghelper.cpp
@@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE
*/
-static const int buttonRoleLayouts[2][5][14] =
+static const int buttonRoleLayouts[2][6][14] =
{
// Qt::Horizontal
{
@@ -92,7 +92,15 @@ static const int buttonRoleLayouts[2][5][14] =
// MacModelessLayout
{ QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::Stretch,
QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL,
- QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }
+ QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL },
+
+ // AndroidLayout (neutral, stretch, dismissive, affirmative)
+ // https://material.io/guidelines/components/dialogs.html#dialogs-specs
+ { QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ActionRole,
+ QPlatformDialogHelper::Stretch, QPlatformDialogHelper::RejectRole | QPlatformDialogHelper::Reverse,
+ QPlatformDialogHelper::NoRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::DestructiveRole | QPlatformDialogHelper::Reverse,
+ QPlatformDialogHelper::AlternateRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::AcceptRole | QPlatformDialogHelper::Reverse,
+ QPlatformDialogHelper::YesRole | QPlatformDialogHelper::Reverse, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }
},
// Qt::Vertical
@@ -120,10 +128,20 @@ static const int buttonRoleLayouts[2][5][14] =
// MacModelessLayout
{ QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::ApplyRole, QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::Stretch,
QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL,
- QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }
+ QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL },
+
+ // AndroidLayout
+ // (affirmative
+ // dismissive
+ // neutral)
+ // https://material.io/guidelines/components/dialogs.html#dialogs-specs
+ { QPlatformDialogHelper::YesRole, QPlatformDialogHelper::AcceptRole, QPlatformDialogHelper::AlternateRole, QPlatformDialogHelper::DestructiveRole,
+ QPlatformDialogHelper::NoRole, QPlatformDialogHelper::RejectRole, QPlatformDialogHelper::Stretch, QPlatformDialogHelper::ActionRole, QPlatformDialogHelper::ApplyRole,
+ QPlatformDialogHelper::ResetRole, QPlatformDialogHelper::HelpRole, QPlatformDialogHelper::EOL, QPlatformDialogHelper::EOL }
}
};
+
QPlatformDialogHelper::QPlatformDialogHelper()
{
qRegisterMetaType<StandardButton>();
@@ -917,6 +935,8 @@ const int *QPlatformDialogHelper::buttonLayout(Qt::Orientation orientation, Butt
policy = MacLayout;
#elif defined (Q_OS_LINUX) || defined (Q_OS_UNIX)
policy = KdeLayout;
+#elif defined (Q_OS_ANDROID)
+ policy = AndroidLayout;
#else
policy = WinLayout;
#endif
diff --git a/src/gui/kernel/qplatformdialoghelper.h b/src/gui/kernel/qplatformdialoghelper.h
index ed88c19c84..f58dcf17f0 100644
--- a/src/gui/kernel/qplatformdialoghelper.h
+++ b/src/gui/kernel/qplatformdialoghelper.h
@@ -141,13 +141,14 @@ public:
Q_ENUM(ButtonRole)
enum ButtonLayout {
- // keep this in sync with QDialogButtonBox::ButtonLayout and QMessageBox::ButtonLayout
+ // keep this in sync with QDialogButtonBox::ButtonLayout
UnknownLayout = -1,
WinLayout,
MacLayout,
KdeLayout,
GnomeLayout,
- MacModelessLayout
+ MacModelessLayout,
+ AndroidLayout
};
QPlatformDialogHelper();
diff --git a/src/gui/kernel/qplatformdrag.h b/src/gui/kernel/qplatformdrag.h
index 560f984a5b..54e6a667fe 100644
--- a/src/gui/kernel/qplatformdrag.h
+++ b/src/gui/kernel/qplatformdrag.h
@@ -95,7 +95,6 @@ public:
virtual ~QPlatformDrag();
QDrag *currentDrag() const;
- virtual QMimeData *platformDropData() = 0;
virtual Qt::DropAction drag(QDrag *m_drag) = 0;
virtual void cancelDrag();
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index fe1861e08b..873ec3a33b 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -237,6 +237,10 @@ QPlatformServices *QPlatformIntegration::services() const
is required to have this capability.
\value ApplicationIcon The platform supports setting the application icon. (since 5.5)
+
+ \value TopStackedNativeChildWindows The platform supports native child windows via
+ QWindowContainer without having to punch a transparent hole in the
+ backingstore. (since 5.10)
*/
/*!
@@ -260,7 +264,8 @@ QPlatformServices *QPlatformIntegration::services() const
bool QPlatformIntegration::hasCapability(Capability cap) const
{
- return cap == NonFullScreenWindows || cap == NativeWidgets || cap == WindowManagement;
+ return cap == NonFullScreenWindows || cap == NativeWidgets || cap == WindowManagement
+ || cap == TopStackedNativeChildWindows;
}
QPlatformPixmap *QPlatformIntegration::createPlatformPixmap(QPlatformPixmap::PixelType type) const
@@ -387,6 +392,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const
return false;
case ShowIsMaximized:
return false;
+ case ShowShortcutsInContextMenus:
+ return QPlatformTheme::defaultThemeHint(QPlatformTheme::ShowShortcutsInContextMenus);
case PasswordMaskDelay:
return QPlatformTheme::defaultThemeHint(QPlatformTheme::PasswordMaskDelay);
case PasswordMaskCharacter:
@@ -622,4 +629,26 @@ void QPlatformIntegration::setApplicationIcon(const QIcon &icon) const
Q_UNUSED(icon);
}
+#if QT_CONFIG(vulkan)
+
+/*!
+ Factory function for QPlatformVulkanInstance. The \a instance parameter is a
+ pointer to the instance for which a platform-specific backend needs to be
+ created.
+
+ Returns a pointer to a QPlatformOpenGLContext instance or \c NULL if the context could
+ not be created.
+
+ \sa QVulkanInstance
+ \since 5.10
+*/
+QPlatformVulkanInstance *QPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
+{
+ Q_UNUSED(instance);
+ qWarning("This plugin does not support createPlatformVulkanInstance");
+ return nullptr;
+}
+
+#endif // QT_CONFIG(vulkan)
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index 0449e0b4c8..eeaa7574f7 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -78,6 +78,8 @@ class QPlatformSessionManager;
class QKeyEvent;
class QPlatformOffscreenSurface;
class QOffscreenSurface;
+class QPlatformVulkanInstance;
+class QVulkanInstance;
class Q_GUI_EXPORT QPlatformIntegration
{
@@ -99,7 +101,8 @@ public:
RasterGLSurface,
AllGLFunctionsQueryable,
ApplicationIcon,
- SwitchableWidgetComposition
+ SwitchableWidgetComposition,
+ TopStackedNativeChildWindows
};
virtual ~QPlatformIntegration() { }
@@ -160,6 +163,7 @@ public:
ItemViewActivateItemOnSingleClick,
UiEffects,
WheelScrollLines,
+ ShowShortcutsInContextMenus,
};
virtual QVariant styleHint(StyleHint hint) const;
@@ -188,6 +192,10 @@ public:
virtual void beep() const;
+#if QT_CONFIG(vulkan)
+ virtual QPlatformVulkanInstance *createPlatformVulkanInstance(QVulkanInstance *instance) const;
+#endif
+
protected:
void screenAdded(QPlatformScreen *screen, bool isPrimary = false);
void destroyScreen(QPlatformScreen *screen);
diff --git a/src/gui/kernel/qplatformmenu.cpp b/src/gui/kernel/qplatformmenu.cpp
index 1eb146dd0f..0d76f2039d 100644
--- a/src/gui/kernel/qplatformmenu.cpp
+++ b/src/gui/kernel/qplatformmenu.cpp
@@ -45,6 +45,37 @@
QT_BEGIN_NAMESPACE
+QPlatformMenuItem::QPlatformMenuItem()
+{
+ m_tag = reinterpret_cast<quintptr>(this);
+}
+
+void QPlatformMenuItem::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+quintptr QPlatformMenuItem::tag() const
+{
+ return m_tag;
+}
+
+QPlatformMenu::QPlatformMenu()
+{
+ m_tag = reinterpret_cast<quintptr>(this);
+}
+
+void QPlatformMenu::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+quintptr QPlatformMenu::tag() const
+{
+ return m_tag;
+
+}
+
QPlatformMenuItem *QPlatformMenu::createMenuItem() const
{
return QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem();
diff --git a/src/gui/kernel/qplatformmenu.h b/src/gui/kernel/qplatformmenu.h
index f8561445b1..e3fa5c71b1 100644
--- a/src/gui/kernel/qplatformmenu.h
+++ b/src/gui/kernel/qplatformmenu.h
@@ -62,6 +62,8 @@ class Q_GUI_EXPORT QPlatformMenuItem : public QObject
{
Q_OBJECT
public:
+ QPlatformMenuItem();
+
// copied from, and must stay in sync with, QAction menu roles.
enum MenuRole { NoRole = 0, TextHeuristicRole, ApplicationSpecificRole, AboutQtRole,
AboutRole, PreferencesRole, QuitRole,
@@ -71,8 +73,8 @@ public:
RoleCount };
Q_ENUM(MenuRole)
- virtual void setTag(quintptr tag) = 0;
- virtual quintptr tag()const = 0;
+ virtual void setTag(quintptr tag);
+ virtual quintptr tag() const;
virtual void setText(const QString &text) = 0;
virtual void setIcon(const QIcon &icon) = 0;
@@ -94,12 +96,17 @@ public:
Q_SIGNALS:
void activated();
void hovered();
+
+private:
+ quintptr m_tag;
};
class Q_GUI_EXPORT QPlatformMenu : public QObject
{
Q_OBJECT
public:
+ QPlatformMenu();
+
enum MenuType { DefaultMenu = 0, EditMenu };
Q_ENUM(MenuType)
@@ -108,8 +115,8 @@ public:
virtual void syncMenuItem(QPlatformMenuItem *menuItem) = 0;
virtual void syncSeparatorsCollapsible(bool enable) = 0;
- virtual void setTag(quintptr tag) = 0;
- virtual quintptr tag()const = 0;
+ virtual void setTag(quintptr tag);
+ virtual quintptr tag() const;
virtual void setText(const QString &text) = 0;
virtual void setIcon(const QIcon &icon) = 0;
@@ -138,6 +145,9 @@ public:
Q_SIGNALS:
void aboutToShow();
void aboutToHide();
+
+private:
+ quintptr m_tag;
};
class Q_GUI_EXPORT QPlatformMenuBar : public QObject
diff --git a/src/gui/kernel/qplatformoffscreensurface.h b/src/gui/kernel/qplatformoffscreensurface.h
index 7f2e0d475b..be15a98e28 100644
--- a/src/gui/kernel/qplatformoffscreensurface.h
+++ b/src/gui/kernel/qplatformoffscreensurface.h
@@ -64,13 +64,13 @@ class Q_GUI_EXPORT QPlatformOffscreenSurface : public QPlatformSurface
Q_DECLARE_PRIVATE(QPlatformOffscreenSurface)
public:
explicit QPlatformOffscreenSurface(QOffscreenSurface *offscreenSurface);
- virtual ~QPlatformOffscreenSurface();
+ ~QPlatformOffscreenSurface() override;
QOffscreenSurface *offscreenSurface() const;
QPlatformScreen *screen() const;
- virtual QSurfaceFormat format() const Q_DECL_OVERRIDE;
+ virtual QSurfaceFormat format() const override;
virtual bool isValid() const;
protected:
diff --git a/src/gui/kernel/qplatformsystemtrayicon.cpp b/src/gui/kernel/qplatformsystemtrayicon.cpp
index 5481997b3c..296beda0f9 100644
--- a/src/gui/kernel/qplatformsystemtrayicon.cpp
+++ b/src/gui/kernel/qplatformsystemtrayicon.cpp
@@ -140,10 +140,19 @@ QPlatformSystemTrayIcon::~QPlatformSystemTrayIcon()
*/
/*!
+ \fn void QPlatformSystemTrayIcon::contextMenuRequested(QPoint globalPos, const QPlatformScreen *screen)
+ This signal is emitted when the context menu is requested.
+ In particular, on platforms where createMenu() returns nullptr,
+ its emission will cause QSystemTrayIcon to show a QMenu-based menu.
+ \sa activated()
+ \since 5.10
+*/
+
+/*!
\fn void QPlatformSystemTrayIcon::activated(QPlatformSystemTrayIcon::ActivationReason reason)
This signal is emitted when the user activates the system tray icon.
\a reason specifies the reason for activation.
- \sa QSystemTrayIcon::ActivationReason
+ \sa QSystemTrayIcon::ActivationReason, contextMenuRequested()
*/
/*!
diff --git a/src/gui/kernel/qplatformsystemtrayicon.h b/src/gui/kernel/qplatformsystemtrayicon.h
index c52dbfbd78..948a6c099d 100644
--- a/src/gui/kernel/qplatformsystemtrayicon.h
+++ b/src/gui/kernel/qplatformsystemtrayicon.h
@@ -49,6 +49,7 @@
QT_BEGIN_NAMESPACE
class QPlatformMenu;
+class QPlatformScreen;
class QIcon;
class QString;
class QRect;
@@ -88,6 +89,7 @@ public:
Q_SIGNALS:
void activated(QPlatformSystemTrayIcon::ActivationReason reason);
+ void contextMenuRequested(QPoint globalPos, const QPlatformScreen *screen);
void messageClicked();
};
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index 878f656f2e..cd3966fb47 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -161,6 +161,8 @@ QT_BEGIN_NAMESPACE
The default value is double the MouseDoubleClickDistance, or 10 logical pixels
if that is not specified.
+ \value ShowShortcutsInContextMenus (bool) Whether to display shortcut key sequences in context menus.
+
\sa themeHint(), QStyle::pixelMetric()
*/
@@ -516,6 +518,8 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
return QVariant(QStringList());
case QPlatformTheme::StyleNames:
return QVariant(QStringList());
+ case QPlatformTheme::ShowShortcutsInContextMenus:
+ return QVariant(false);
case TextCursorWidth:
return QVariant(1);
case DropShadow:
@@ -527,7 +531,7 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
case UiEffects:
return QVariant(int(0));
case SpellCheckUnderlineStyle:
- return QVariant(int(QTextCharFormat::SpellCheckUnderline));
+ return QVariant(int(QTextCharFormat::WaveUnderline));
case TabFocusBehavior:
return QVariant(int(Qt::TabFocusAllControls));
case IconPixmapSizes:
diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h
index 2ba2f8669f..f4ff418db6 100644
--- a/src/gui/kernel/qplatformtheme.h
+++ b/src/gui/kernel/qplatformtheme.h
@@ -115,7 +115,8 @@ public:
MousePressAndHoldInterval,
MouseDoubleClickDistance,
WheelScrollLines,
- TouchDoubleTapDistance
+ TouchDoubleTapDistance,
+ ShowShortcutsInContextMenus
};
enum DialogType {
diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp
index 23e492ee7a..7a4be7b8a8 100644
--- a/src/gui/kernel/qplatformwindow.cpp
+++ b/src/gui/kernel/qplatformwindow.cpp
@@ -71,6 +71,17 @@ QPlatformWindow::~QPlatformWindow()
}
/*!
+ Called as part of QWindow::create(), after constructing
+ the window. Platforms should prefer to do initialization
+ here instead of in the constructor, as the platform window
+ object will be fully constructed, and associated to the
+ corresponding QWindow, allowing synchronous event delivery.
+*/
+void QPlatformWindow::initialize()
+{
+}
+
+/*!
Returns the window which belongs to the QPlatformWindow
*/
QWindow *QPlatformWindow::window() const
@@ -105,10 +116,18 @@ QSurfaceFormat QPlatformWindow::format() const
}
/*!
- This function is called by Qt whenever a window is moved or the window is resized. The resize
- can happen programatically(from ie. user application) or by the window manager. This means that
- there is no need to call this function specifically from the window manager callback, instead
- call QWindowSystemInterface::handleGeometryChange(QWindow *w, const QRect &newRect);
+ This function is called by Qt whenever a window is moved or resized using the QWindow API.
+
+ Unless you also override QPlatformWindow::geometry(), you need to call the baseclass
+ implementation of this function in any override of QPlatformWindow::setGeometry(), as
+ QWindow::geometry() is expected to report back the set geometry until a confirmation
+ (or rejection) of the new geometry comes back from the window manager and is reported
+ via QWindowSystemInterface::handleGeometryChange().
+
+ Window move/resizes can also be triggered spontaneously by the window manager, or as a
+ response to an earlier requested move/resize via the Qt APIs. There is no need to call
+ this function from the window manager callback, instead call
+ QWindowSystemInterface::handleGeometryChange().
The position(x, y) part of the rect might be inclusive or exclusive of the window frame
as returned by frameMargins(). You can detect this in the plugin by checking
@@ -271,7 +290,7 @@ QPoint QPlatformWindow::mapFromGlobal(const QPoint &pos) const
Qt::WindowActive can be ignored.
*/
-void QPlatformWindow::setWindowState(Qt::WindowState)
+void QPlatformWindow::setWindowState(Qt::WindowStates)
{
}
diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h
index 2bee55c7e0..cf5f38d249 100644
--- a/src/gui/kernel/qplatformwindow.h
+++ b/src/gui/kernel/qplatformwindow.h
@@ -72,14 +72,16 @@ class Q_GUI_EXPORT QPlatformWindow : public QPlatformSurface
Q_DECLARE_PRIVATE(QPlatformWindow)
public:
explicit QPlatformWindow(QWindow *window);
- virtual ~QPlatformWindow();
+ ~QPlatformWindow() override;
+
+ virtual void initialize();
QWindow *window() const;
QPlatformWindow *parent() const;
QPlatformScreen *screen() const;
- virtual QSurfaceFormat format() const Q_DECL_OVERRIDE;
+ virtual QSurfaceFormat format() const override;
virtual void setGeometry(const QRect &rect);
virtual QRect geometry() const;
@@ -90,7 +92,7 @@ public:
virtual void setVisible(bool visible);
virtual void setWindowFlags(Qt::WindowFlags flags);
- virtual void setWindowState(Qt::WindowState state);
+ virtual void setWindowState(Qt::WindowStates state);
virtual WId winId() const;
virtual void setParent(const QPlatformWindow *window);
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 96f75f37eb..479e228e27 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -384,6 +384,10 @@ QRect QScreen::geometry() const
The available geometry is the geometry excluding window manager reserved areas
such as task bars and system menus.
+
+ Note, on X11 this will return the true available geometry only on systems with one monitor and
+ if window manager has set _NET_WORKAREA atom. In all other cases this is equal to geometry().
+ This is a limitation in X11 window manager specification.
*/
QRect QScreen::availableGeometry() const
{
diff --git a/src/gui/kernel/qsimpledrag.cpp b/src/gui/kernel/qsimpledrag.cpp
index a1e25dc53c..99aaed0444 100644
--- a/src/gui/kernel/qsimpledrag.cpp
+++ b/src/gui/kernel/qsimpledrag.cpp
@@ -353,13 +353,6 @@ QSimpleDrag::QSimpleDrag() : m_current_window(0)
{
}
-QMimeData *QSimpleDrag::platformDropData()
-{
- if (drag())
- return drag()->mimeData();
- return 0;
-}
-
void QSimpleDrag::startDrag()
{
QBasicDrag::startDrag();
diff --git a/src/gui/kernel/qsimpledrag_p.h b/src/gui/kernel/qsimpledrag_p.h
index 0b8a0bc703..45c13e43b2 100644
--- a/src/gui/kernel/qsimpledrag_p.h
+++ b/src/gui/kernel/qsimpledrag_p.h
@@ -125,7 +125,6 @@ class Q_GUI_EXPORT QSimpleDrag : public QBasicDrag
{
public:
QSimpleDrag();
- virtual QMimeData *platformDropData() Q_DECL_OVERRIDE;
protected:
virtual void startDrag() Q_DECL_OVERRIDE;
diff --git a/src/gui/kernel/qstylehints.cpp b/src/gui/kernel/qstylehints.cpp
index 85c0768e35..0850228ee5 100644
--- a/src/gui/kernel/qstylehints.cpp
+++ b/src/gui/kernel/qstylehints.cpp
@@ -365,6 +365,17 @@ bool QStyleHints::showIsMaximized() const
}
/*!
+ \property QStyleHints::showShortcutsInContextMenus
+ \since 5.10
+ \brief \c true if the platform normally shows shortcut key sequences in
+ context menus, otherwise \c false.
+*/
+bool QStyleHints::showShortcutsInContextMenus() const
+{
+ return themeableHint(QPlatformTheme::ShowShortcutsInContextMenus, QPlatformIntegration::ShowShortcutsInContextMenus).toBool();
+}
+
+/*!
\property QStyleHints::passwordMaskDelay
\brief the time, in milliseconds, a typed letter is displayed unshrouded
in a text input field in password mode.
diff --git a/src/gui/kernel/qstylehints.h b/src/gui/kernel/qstylehints.h
index b9bf428edd..2c2e048b15 100644
--- a/src/gui/kernel/qstylehints.h
+++ b/src/gui/kernel/qstylehints.h
@@ -64,6 +64,7 @@ class Q_GUI_EXPORT QStyleHints : public QObject
Q_PROPERTY(bool setFocusOnTouchRelease READ setFocusOnTouchRelease STORED false CONSTANT FINAL)
Q_PROPERTY(bool showIsFullScreen READ showIsFullScreen STORED false CONSTANT FINAL)
Q_PROPERTY(bool showIsMaximized READ showIsMaximized STORED false CONSTANT FINAL)
+ Q_PROPERTY(bool showShortcutsInContextMenus READ showShortcutsInContextMenus STORED false CONSTANT FINAL)
Q_PROPERTY(int startDragDistance READ startDragDistance NOTIFY startDragDistanceChanged FINAL)
Q_PROPERTY(int startDragTime READ startDragTime NOTIFY startDragTimeChanged FINAL)
Q_PROPERTY(int startDragVelocity READ startDragVelocity STORED false CONSTANT FINAL)
@@ -90,6 +91,7 @@ public:
int cursorFlashTime() const;
bool showIsFullScreen() const;
bool showIsMaximized() const;
+ bool showShortcutsInContextMenus() const;
int passwordMaskDelay() const;
QChar passwordMaskCharacter() const;
qreal fontSmoothingGamma() const;
diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp
index 3cdd11de8c..63651ee822 100644
--- a/src/gui/kernel/qsurface.cpp
+++ b/src/gui/kernel/qsurface.cpp
@@ -78,6 +78,8 @@ QT_BEGIN_NAMESPACE
requires the use of private API.
\value OpenVGSurface The surface is an OpenVG compatible surface and can be used
in conjunction with OpenVG contexts.
+ \value VulkanSurface The surface is a Vulkan compatible surface and can be used
+ in conjunction with the Vulkan graphics API.
*/
diff --git a/src/gui/kernel/qsurface.h b/src/gui/kernel/qsurface.h
index a96b7a6422..7e09449d12 100644
--- a/src/gui/kernel/qsurface.h
+++ b/src/gui/kernel/qsurface.h
@@ -66,6 +66,7 @@ public:
OpenGLSurface,
RasterGLSurface,
OpenVGSurface,
+ VulkanSurface
};
virtual ~QSurface();
diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp
index 000d727380..574310f554 100644
--- a/src/gui/kernel/qsurfaceformat.cpp
+++ b/src/gui/kernel/qsurfaceformat.cpp
@@ -73,6 +73,7 @@ public:
, major(2)
, minor(0)
, swapInterval(1) // default to vsync
+ , colorSpace(QSurfaceFormat::DefaultColorSpace)
{
}
@@ -91,7 +92,8 @@ public:
profile(other->profile),
major(other->major),
minor(other->minor),
- swapInterval(other->swapInterval)
+ swapInterval(other->swapInterval),
+ colorSpace(other->colorSpace)
{
}
@@ -110,6 +112,7 @@ public:
int major;
int minor;
int swapInterval;
+ QSurfaceFormat::ColorSpace colorSpace;
};
/*!
@@ -124,6 +127,12 @@ public:
contains surface configuration parameters such as OpenGL profile and
version for rendering, whether or not to enable stereo buffers, and swap
behaviour.
+
+ \note When troubleshooting context or window format issues, it can be
+ helpful to enable the logging category \c{qt.qpa.gl}. Depending on the
+ platform, this may print useful debug information when it comes to OpenGL
+ initialization and the native visual or framebuffer configurations which
+ QSurfaceFormat gets mapped to.
*/
/*!
@@ -199,6 +208,22 @@ public:
*/
/*!
+ \enum QSurfaceFormat::ColorSpace
+
+ This enum is used to specify the preferred color space, controlling if the
+ window's associated default framebuffer is able to do updates and blending
+ in a given encoding instead of the standard linear operations.
+
+ \value DefaultColorSpace The default, unspecified color space.
+
+ \value sRGBColorSpace When \c{GL_ARB_framebuffer_sRGB} or
+ \c{GL_EXT_framebuffer_sRGB} is supported by the platform and this value is
+ set, the window will be created with an sRGB-capable default
+ framebuffer. Note that some platforms may return windows with a sRGB-capable
+ default framebuffer even when not requested explicitly.
+ */
+
+/*!
Constructs a default initialized QSurfaceFormat.
\note By default OpenGL 2.0 is requested since this provides the highest
@@ -736,6 +761,47 @@ int QSurfaceFormat::swapInterval() const
return d->swapInterval;
}
+/*!
+ Sets the preferred \a colorSpace.
+
+ For example, this allows requesting windows with default framebuffers that
+ are sRGB-capable on platforms that support it.
+
+ \note When the requested color space is not supported by the platform, the
+ request is ignored. Query the QSurfaceFormat after window creation to verify
+ if the color space request could be honored or not.
+
+ \note This setting controls if the default framebuffer of the window is
+ capable of updates and blending in a given color space. It does not change
+ applications' output by itself. The applications' rendering code will still
+ have to opt in via the appropriate OpenGL calls to enable updates and
+ blending to be performed in the given color space instead of using the
+ standard linear operations.
+
+ \since 5.10
+
+ \sa colorSpace()
+ */
+void QSurfaceFormat::setColorSpace(ColorSpace colorSpace)
+{
+ if (d->colorSpace != colorSpace) {
+ detach();
+ d->colorSpace = colorSpace;
+ }
+}
+
+/*!
+ \return the color space.
+
+ \since 5.10
+
+ \sa setColorSpace()
+*/
+QSurfaceFormat::ColorSpace QSurfaceFormat::colorSpace() const
+{
+ return d->colorSpace;
+}
+
Q_GLOBAL_STATIC(QSurfaceFormat, qt_default_surface_format)
/*!
@@ -841,6 +907,7 @@ QDebug operator<<(QDebug dbg, const QSurfaceFormat &f)
<< ", samples " << d->numSamples
<< ", swapBehavior " << d->swapBehavior
<< ", swapInterval " << d->swapInterval
+ << ", colorSpace " << d->colorSpace
<< ", profile " << d->profile
<< ')';
diff --git a/src/gui/kernel/qsurfaceformat.h b/src/gui/kernel/qsurfaceformat.h
index 246163609e..ed63eb8bbf 100644
--- a/src/gui/kernel/qsurfaceformat.h
+++ b/src/gui/kernel/qsurfaceformat.h
@@ -85,6 +85,12 @@ public:
};
Q_ENUM(OpenGLContextProfile)
+ enum ColorSpace {
+ DefaultColorSpace,
+ sRGBColorSpace
+ };
+ Q_ENUM(ColorSpace)
+
QSurfaceFormat();
/*implicit*/ QSurfaceFormat(FormatOptions options);
QSurfaceFormat(const QSurfaceFormat &other);
@@ -145,6 +151,9 @@ public:
int swapInterval() const;
void setSwapInterval(int interval);
+ ColorSpace colorSpace() const;
+ void setColorSpace(ColorSpace colorSpace);
+
static void setDefaultFormat(const QSurfaceFormat &format);
static QSurfaceFormat defaultFormat();
diff --git a/src/gui/kernel/qtouchdevice.cpp b/src/gui/kernel/qtouchdevice.cpp
index 0f13412fb1..511e92566e 100644
--- a/src/gui/kernel/qtouchdevice.cpp
+++ b/src/gui/kernel/qtouchdevice.cpp
@@ -235,6 +235,15 @@ bool QTouchDevicePrivate::isRegistered(const QTouchDevice *dev)
return deviceList()->contains(dev);
}
+const QTouchDevice *QTouchDevicePrivate::deviceById(quint8 id)
+{
+ QMutexLocker locker(&devicesMutex);
+ for (const QTouchDevice *dev : *deviceList())
+ if (QTouchDevicePrivate::get(const_cast<QTouchDevice *>(dev))->id == id)
+ return dev;
+ return nullptr;
+}
+
/*!
\internal
*/
diff --git a/src/gui/kernel/qtouchdevice_p.h b/src/gui/kernel/qtouchdevice_p.h
index 18d2af46a7..fc45066c2d 100644
--- a/src/gui/kernel/qtouchdevice_p.h
+++ b/src/gui/kernel/qtouchdevice_p.h
@@ -78,6 +78,7 @@ public:
static void registerDevice(const QTouchDevice *dev);
static void unregisterDevice(const QTouchDevice *dev);
static bool isRegistered(const QTouchDevice *dev);
+ static const QTouchDevice *deviceById(quint8 id);
static QTouchDevicePrivate *get(QTouchDevice *q) { return q->d; }
};
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 9e5b687851..3e5777ad49 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -45,6 +45,7 @@
#ifndef QT_NO_OPENGL
#include <qpa/qplatformopenglcontext.h>
#include "qopenglcontext.h"
+#include "qopenglcontext_p.h"
#endif
#include "qscreen.h"
@@ -117,7 +118,7 @@ QT_BEGIN_NAMESPACE
application, isExposed() will simply return the same value as isVisible().
QWindow::Visibility queried through visibility() is a convenience API
- combining the functions of visible() and windowState().
+ combining the functions of visible() and windowStates().
\section1 Rendering
@@ -318,34 +319,104 @@ void QWindow::setVisibility(Visibility v)
}
}
-void QWindowPrivate::updateVisibility()
+/*
+ Subclasses may override this function to run custom setVisible
+ logic. Subclasses that do so must call the base class implementation
+ at some point to make the native window visible, and must not
+ call QWindow::setVisble() since that will recurse back here.
+*/
+void QWindowPrivate::setVisible(bool visible)
{
Q_Q(QWindow);
- QWindow::Visibility old = visibility;
+ if (this->visible != visible) {
+ this->visible = visible;
+ emit q->visibleChanged(visible);
+ updateVisibility();
+ } else if (platformWindow) {
+ // Visibility hasn't changed, and the platform window is in sync
+ return;
+ }
+
+ if (!platformWindow) {
+ // If we have a parent window, but the parent hasn't been created yet, we
+ // can defer creation until the parent is created or we're re-parented.
+ if (parentWindow && !parentWindow->handle())
+ return;
+
+ // We only need to create the window if it's being shown
+ if (visible)
+ q->create();
+ }
if (visible) {
- switch (windowState) {
- case Qt::WindowMinimized:
- visibility = QWindow::Minimized;
- break;
- case Qt::WindowMaximized:
- visibility = QWindow::Maximized;
- break;
- case Qt::WindowFullScreen:
- visibility = QWindow::FullScreen;
- break;
- case Qt::WindowNoState:
- visibility = QWindow::Windowed;
- break;
- default:
- Q_ASSERT(false);
- break;
+ // remove posted quit events when showing a new window
+ QCoreApplication::removePostedEvents(qApp, QEvent::Quit);
+
+ if (q->type() == Qt::Window) {
+ QGuiApplicationPrivate *app_priv = QGuiApplicationPrivate::instance();
+ QString &firstWindowTitle = app_priv->firstWindowTitle;
+ if (!firstWindowTitle.isEmpty()) {
+ q->setTitle(firstWindowTitle);
+ firstWindowTitle = QString();
+ }
+ if (!app_priv->forcedWindowIcon.isNull())
+ q->setIcon(app_priv->forcedWindowIcon);
+
+ // Handling of the -qwindowgeometry, -geometry command line arguments
+ static bool geometryApplied = false;
+ if (!geometryApplied) {
+ geometryApplied = true;
+ QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(q);
+ }
}
- } else {
- visibility = QWindow::Hidden;
+
+ QShowEvent showEvent;
+ QGuiApplication::sendEvent(q, &showEvent);
}
+ if (q->isModal()) {
+ if (visible)
+ QGuiApplicationPrivate::showModalWindow(q);
+ else
+ QGuiApplicationPrivate::hideModalWindow(q);
+ // QShapedPixmapWindow is used on some platforms for showing a drag pixmap, so don't block
+ // input to this window as it is performing a drag - QTBUG-63846
+ } else if (visible && QGuiApplication::modalWindow() && !qobject_cast<QShapedPixmapWindow *>(q)) {
+ QGuiApplicationPrivate::updateBlockedStatus(q);
+ }
+
+#ifndef QT_NO_CURSOR
+ if (visible && (hasCursor || QGuiApplication::overrideCursor()))
+ applyCursor();
+#endif
+
+ if (platformWindow)
+ platformWindow->setVisible(visible);
+
+ if (!visible) {
+ QHideEvent hideEvent;
+ QGuiApplication::sendEvent(q, &hideEvent);
+ }
+}
+
+void QWindowPrivate::updateVisibility()
+{
+ Q_Q(QWindow);
+
+ QWindow::Visibility old = visibility;
+
+ if (!visible)
+ visibility = QWindow::Hidden;
+ else if (windowState & Qt::WindowMinimized)
+ visibility = QWindow::Minimized;
+ else if (windowState & Qt::WindowFullScreen)
+ visibility = QWindow::FullScreen;
+ else if (windowState & Qt::WindowMaximized)
+ visibility = QWindow::Maximized;
+ else
+ visibility = QWindow::Windowed;
+
if (visibility != old)
emit q->visibilityChanged(visibility);
}
@@ -444,6 +515,8 @@ void QWindowPrivate::create(bool recursive, WId nativeHandle)
return;
}
+ platformWindow->initialize();
+
QObjectList childObjects = q->children();
for (int i = 0; i < childObjects.size(); i ++) {
QObject *object = childObjects.at(i);
@@ -526,75 +599,7 @@ void QWindow::setVisible(bool visible)
{
Q_D(QWindow);
- if (d->visible != visible) {
- d->visible = visible;
- emit visibleChanged(visible);
- d->updateVisibility();
- } else if (d->platformWindow) {
- // Visibility hasn't changed, and the platform window is in sync
- return;
- }
-
- if (!d->platformWindow) {
- // If we have a parent window, but the parent hasn't been created yet, we
- // can defer creation until the parent is created or we're re-parented.
- if (parent() && !parent()->handle())
- return;
-
- // We only need to create the window if it's being shown
- if (visible)
- create();
- }
-
- if (visible) {
- // remove posted quit events when showing a new window
- QCoreApplication::removePostedEvents(qApp, QEvent::Quit);
-
- if (type() == Qt::Window) {
- QGuiApplicationPrivate *app_priv = QGuiApplicationPrivate::instance();
- QString &firstWindowTitle = app_priv->firstWindowTitle;
- if (!firstWindowTitle.isEmpty()) {
- setTitle(firstWindowTitle);
- firstWindowTitle = QString();
- }
- if (!app_priv->forcedWindowIcon.isNull())
- setIcon(app_priv->forcedWindowIcon);
-
- // Handling of the -qwindowgeometry, -geometry command line arguments
- static bool geometryApplied = false;
- if (!geometryApplied) {
- geometryApplied = true;
- QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(this);
- }
- }
-
- QShowEvent showEvent;
- QGuiApplication::sendEvent(this, &showEvent);
- }
-
- if (isModal()) {
- if (visible)
- QGuiApplicationPrivate::showModalWindow(this);
- else
- QGuiApplicationPrivate::hideModalWindow(this);
- // QShapedPixmapWindow is used on some platforms for showing a drag pixmap, so don't block
- // input to this window as it is performing a drag - QTBUG-63846
- } else if (visible && QGuiApplication::modalWindow() && !qobject_cast<QShapedPixmapWindow *>(this)) {
- QGuiApplicationPrivate::updateBlockedStatus(this);
- }
-
-#ifndef QT_NO_CURSOR
- if (visible && (d->hasCursor || QGuiApplication::overrideCursor()))
- d->applyCursor();
-#endif
-
- if (d->platformWindow)
- d->platformWindow->setVisible(visible);
-
- if (!visible) {
- QHideEvent hideEvent;
- QGuiApplication::sendEvent(this, &hideEvent);
- }
+ d->setVisible(visible);
}
bool QWindow::isVisible() const
@@ -970,6 +975,11 @@ QString QWindow::filePath() const
The window icon might be used by the windowing system for example to
decorate the window, and/or in the task switcher.
+
+ \note On \macos, the window title bar icon is meant for windows representing
+ documents, and will only show up if a file path is also set.
+
+ \sa setFilePath()
*/
void QWindow::setIcon(const QIcon &icon)
{
@@ -982,7 +992,7 @@ void QWindow::setIcon(const QIcon &icon)
}
/*!
- \brief Sets the window's icon in the windowing system
+ \brief Returns the window's icon in the windowing system
\sa setIcon()
*/
@@ -1065,15 +1075,12 @@ qreal QWindow::opacity() const
The window manager may or may not choose to display any areas of the window
not included in the mask, thus it is the application's responsibility to
clear to transparent the areas that are not part of the mask.
-
- Setting the mask before the window has been created has no effect.
*/
void QWindow::setMask(const QRegion &region)
{
Q_D(QWindow);
- if (!d->platformWindow)
- return;
- d->platformWindow->setMask(QHighDpi::toNativeLocalRegion(region, this));
+ if (d->platformWindow)
+ d->platformWindow->setMask(QHighDpi::toNativeLocalRegion(region, this));
d->mask = region;
}
@@ -1220,6 +1227,17 @@ qreal QWindow::devicePixelRatio() const
return d->platformWindow->devicePixelRatio() * QHighDpiScaling::factor(this);
}
+Qt::WindowState QWindowPrivate::effectiveState(Qt::WindowStates state)
+{
+ if (state & Qt::WindowMinimized)
+ return Qt::WindowMinimized;
+ else if (state & Qt::WindowFullScreen)
+ return Qt::WindowFullScreen;
+ else if (state & Qt::WindowMaximized)
+ return Qt::WindowMaximized;
+ return Qt::WindowNoState;
+}
+
/*!
\brief set the screen-occupation state of the window
@@ -1228,31 +1246,69 @@ qreal QWindow::devicePixelRatio() const
The enum value Qt::WindowActive is not an accepted parameter.
- \sa showNormal(), showFullScreen(), showMinimized(), showMaximized()
+ \sa showNormal(), showFullScreen(), showMinimized(), showMaximized(), setWindowStates()
*/
void QWindow::setWindowState(Qt::WindowState state)
{
- if (state == Qt::WindowActive) {
- qWarning("QWindow::setWindowState does not accept Qt::WindowActive");
- return;
- }
+ setWindowStates(state);
+}
+
+/*!
+ \brief set the screen-occupation state of the window
+ \since 5.10
+
+ The window \a state represents whether the window appears in the
+ windowing system as maximized, minimized and/or fullscreen.
+ The window can be in a combination of several states. For example, if
+ the window is both minimized and maximized, the window will appear
+ minimized, but clicking on the task bar entry will restore it to the
+ maximized state.
+
+ The enum value Qt::WindowActive should not be set.
+
+ \sa showNormal(), showFullScreen(), showMinimized(), showMaximized()
+ */
+void QWindow::setWindowStates(Qt::WindowStates state)
+{
Q_D(QWindow);
+ if (state & Qt::WindowActive) {
+ qWarning("QWindow::setWindowStates does not accept Qt::WindowActive");
+ state &= ~Qt::WindowActive;
+ }
+
if (d->platformWindow)
d->platformWindow->setWindowState(state);
d->windowState = state;
- emit windowStateChanged(d->windowState);
+ emit windowStateChanged(QWindowPrivate::effectiveState(d->windowState));
d->updateVisibility();
}
/*!
\brief the screen-occupation state of the window
- \sa setWindowState()
+ \sa setWindowState(), windowStates()
*/
Qt::WindowState QWindow::windowState() const
{
Q_D(const QWindow);
+ return QWindowPrivate::effectiveState(d->windowState);
+}
+
+/*!
+ \brief the screen-occupation state of the window
+ \since 5.10
+
+ The window can be in a combination of several states. For example, if
+ the window is both minimized and maximized, the window will appear
+ minimized, but clicking on the task bar entry will restore it to
+ the maximized state.
+
+ \sa setWindowStates()
+*/
+Qt::WindowStates QWindow::windowStates() const
+{
+ Q_D(const QWindow);
return d->windowState;
}
@@ -1260,7 +1316,7 @@ Qt::WindowState QWindow::windowState() const
\fn QWindow::windowStateChanged(Qt::WindowState windowState)
This signal is emitted when the \a windowState changes, either
- by being set explicitly with setWindowState(), or automatically when
+ by being set explicitly with setWindowStates(), or automatically when
the user clicks one of the titlebar buttons or by other means.
*/
@@ -1835,11 +1891,16 @@ void QWindowPrivate::destroy()
QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
QGuiApplication::sendEvent(q, &e);
- delete platformWindow;
+ // Unset platformWindow before deleting, so that the destructor of the
+ // platform window does not recurse back into the platform window via
+ // this window during destruction (e.g. as a result of platform events).
+ QPlatformWindow *pw = platformWindow;
+ platformWindow = nullptr;
+ delete pw;
+
resizeEventPending = true;
receivedExpose = false;
exposed = false;
- platformWindow = 0;
if (wasVisible)
maybeQuitOnLastWindowClosed();
@@ -2006,42 +2067,42 @@ void QWindow::hide()
/*!
Shows the window as minimized.
- Equivalent to calling setWindowState(Qt::WindowMinimized) and then
+ Equivalent to calling setWindowStates(Qt::WindowMinimized) and then
setVisible(true).
- \sa setWindowState(), setVisible()
+ \sa setWindowStates(), setVisible()
*/
void QWindow::showMinimized()
{
- setWindowState(Qt::WindowMinimized);
+ setWindowStates(Qt::WindowMinimized);
setVisible(true);
}
/*!
Shows the window as maximized.
- Equivalent to calling setWindowState(Qt::WindowMaximized) and then
+ Equivalent to calling setWindowStates(Qt::WindowMaximized) and then
setVisible(true).
- \sa setWindowState(), setVisible()
+ \sa setWindowStates(), setVisible()
*/
void QWindow::showMaximized()
{
- setWindowState(Qt::WindowMaximized);
+ setWindowStates(Qt::WindowMaximized);
setVisible(true);
}
/*!
Shows the window as fullscreen.
- Equivalent to calling setWindowState(Qt::WindowFullScreen) and then
+ Equivalent to calling setWindowStates(Qt::WindowFullScreen) and then
setVisible(true).
- \sa setWindowState(), setVisible()
+ \sa setWindowStates(), setVisible()
*/
void QWindow::showFullScreen()
{
- setWindowState(Qt::WindowFullScreen);
+ setWindowStates(Qt::WindowFullScreen);
setVisible(true);
#if !defined Q_OS_QNX // On QNX this window will be activated anyway from libscreen
// activating it here before libscreen activates it causes problems
@@ -2052,14 +2113,14 @@ void QWindow::showFullScreen()
/*!
Shows the window as normal, i.e. neither maximized, minimized, nor fullscreen.
- Equivalent to calling setWindowState(Qt::WindowNoState) and then
+ Equivalent to calling setWindowStates(Qt::WindowNoState) and then
setVisible(true).
- \sa setWindowState(), setVisible()
+ \sa setWindowStates(), setVisible()
*/
void QWindow::showNormal()
{
- setWindowState(Qt::WindowNoState);
+ setWindowStates(Qt::WindowNoState);
setVisible(true);
}
@@ -2255,7 +2316,7 @@ bool QWindow::event(QEvent *ev)
case QEvent::WindowStateChange: {
Q_D(QWindow);
- emit windowStateChanged(d->windowState);
+ emit windowStateChanged(QWindowPrivate::effectiveState(d->windowState));
d->updateVisibility();
break;
}
@@ -2517,7 +2578,7 @@ QPoint QWindowPrivate::globalPosition() const
QPoint offset = q->position();
for (const QWindow *p = q->parent(); p; p = p->parent()) {
QPlatformWindow *pw = p->handle();
- if (pw && pw->isForeignWindow()) {
+ if (pw && (pw->isForeignWindow() || pw->isEmbedded())) {
// Use mapToGlobal() for foreign windows
offset += p->mapToGlobal(QPoint(0, 0));
break;
@@ -2576,6 +2637,13 @@ QWindow *QWindowPrivate::topLevelWindow() const
return window;
}
+#if QT_CONFIG(opengl)
+QOpenGLContext *QWindowPrivate::shareContext() const
+{
+ return qt_gl_global_share_context();
+};
+#endif
+
/*!
Creates a local representation of a window created by another process or by
using native libraries below Qt.
@@ -2722,6 +2790,8 @@ bool QWindowPrivate::applyCursor()
if (!platformWindow)
return true;
QCursor *c = QGuiApplication::overrideCursor();
+ if (c != nullptr && platformCursor->capabilities().testFlag(QPlatformCursor::OverrideCursor))
+ return true;
if (!c && hasCursor)
c = &cursor;
platformCursor->changeCursor(c, q);
@@ -2771,6 +2841,30 @@ QDebug operator<<(QDebug debug, const QWindow *window)
}
#endif // !QT_NO_DEBUG_STREAM
+#if QT_CONFIG(vulkan)
+
+/*!
+ Associates this window with the specified Vulkan \a instance.
+
+ \a instance must stay valid as long as this QWindow instance exists.
+ */
+void QWindow::setVulkanInstance(QVulkanInstance *instance)
+{
+ Q_D(QWindow);
+ d->vulkanInstance = instance;
+}
+
+/*!
+ \return the associrated Vulkan instance or \c null if there is none.
+ */
+QVulkanInstance *QWindow::vulkanInstance() const
+{
+ Q_D(const QWindow);
+ return d->vulkanInstance;
+}
+
+#endif // QT_CONFIG(vulkan)
+
QT_END_NAMESPACE
#include "moc_qwindow.cpp"
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index db8e828e70..44ff054fa3 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -88,6 +88,9 @@ class QWindowContainer;
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
#endif
+#if QT_CONFIG(vulkan)
+class QVulkanInstance;
+#endif
class Q_GUI_EXPORT QWindow : public QObject, public QSurface
{
@@ -189,7 +192,9 @@ public:
qreal devicePixelRatio() const;
Qt::WindowState windowState() const;
+ Qt::WindowStates windowStates() const;
void setWindowState(Qt::WindowState state);
+ void setWindowStates(Qt::WindowStates states);
void setTransientParent(QWindow *parent);
QWindow *transientParent() const;
@@ -213,8 +218,6 @@ public:
void setBaseSize(const QSize &size);
void setSizeIncrement(const QSize &size);
- void setGeometry(int posx, int posy, int w, int h);
- void setGeometry(const QRect &rect);
QRect geometry() const;
QMargins frameMargins() const;
@@ -267,6 +270,11 @@ public:
static QWindow *fromWinId(WId id);
+#if QT_CONFIG(vulkan)
+ void setVulkanInstance(QVulkanInstance *instance);
+ QVulkanInstance *vulkanInstance() const;
+#endif
+
public Q_SLOTS:
Q_REVISION(1) void requestActivate();
@@ -290,6 +298,8 @@ public Q_SLOTS:
void setY(int arg);
void setWidth(int arg);
void setHeight(int arg);
+ void setGeometry(int posx, int posy, int w, int h);
+ void setGeometry(const QRect &rect);
void setMinimumWidth(int w);
void setMinimumHeight(int h);
diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h
index 568aa1e2fc..7ef73eb410 100644
--- a/src/gui/kernel/qwindow_p.h
+++ b/src/gui/kernel/qwindow_p.h
@@ -105,6 +105,9 @@ public:
, hasCursor(false)
#endif
, compositing(false)
+#if QT_CONFIG(vulkan)
+ , vulkanInstance(nullptr)
+#endif
{
isWindow = true;
}
@@ -127,8 +130,13 @@ public:
QWindow *topLevelWindow() const;
+#if QT_CONFIG(opengl)
+ virtual QOpenGLContext *shareContext() const;
+#endif
+
virtual QWindow *eventReceiver() { Q_Q(QWindow); return q; }
+ virtual void setVisible(bool visible);
void updateVisibility();
void _q_clearAlert();
@@ -153,6 +161,8 @@ public:
static QWindowPrivate *get(QWindow *window) { return window->d_func(); }
+ static Qt::WindowState effectiveState(Qt::WindowStates);
+
QWindow::SurfaceType surfaceType;
Qt::WindowFlags windowFlags;
QWindow *parentWindow;
@@ -165,7 +175,7 @@ public:
QString windowFilePath;
QIcon windowIcon;
QRect geometry;
- Qt::WindowState windowState;
+ Qt::WindowStates windowState;
QWindow::Visibility visibility;
bool resizeEventPending;
bool receivedExpose;
@@ -196,6 +206,10 @@ public:
bool compositing;
QElapsedTimer lastComposeTime;
+
+#if QT_CONFIG(vulkan)
+ QVulkanInstance *vulkanInstance;
+#endif
};
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 13f45d236e..c47d940e4a 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -66,7 +66,7 @@ extern QPointer<QWindow> qt_last_mouse_receiver;
// ------------------- QWindowSystemInterfacePrivate -------------------
-/*!
+/*
Handles a window system event asynchronously by posting the event to Qt Gui.
This function posts the event on the window system event queue and wakes the
@@ -82,7 +82,7 @@ bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterfa
return true;
}
-/*!
+/*
Handles a window system event synchronously.
Qt Gui will process the event immediately. The return value indicates if Qt
@@ -112,7 +112,7 @@ bool QWindowSystemInterfacePrivate::handleWindowSystemEvent<QWindowSystemInterfa
return accepted;
}
-/*!
+/*
Handles a window system event.
By default this function posts the event on the window system event queue and
@@ -247,14 +247,14 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowActivated, QWindow *window, Qt::Fo
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowStateChanged, QWindow *window, Qt::WindowState newState, int oldState)
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleWindowStateChanged, QWindow *window, Qt::WindowStates newState, int oldState)
{
Q_ASSERT(window);
if (oldState < Qt::WindowNoState)
oldState = window->windowState();
QWindowSystemInterfacePrivate::WindowStateChangedEvent *e =
- new QWindowSystemInterfacePrivate::WindowStateChangedEvent(window, newState, Qt::WindowState(oldState));
+ new QWindowSystemInterfacePrivate::WindowStateChangedEvent(window, newState, Qt::WindowStates(oldState));
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
@@ -280,12 +280,25 @@ QT_DEFINE_QPA_EVENT_HANDLER(void, handleApplicationStateChanged, Qt::Application
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
-/*!
- If \a oldRect is null, Qt will use the previously reported geometry instead.
- */
-QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect, const QRect &oldRect)
+QWindowSystemInterfacePrivate::GeometryChangeEvent::GeometryChangeEvent(QWindow *window, const QRect &newGeometry)
+ : WindowSystemEvent(GeometryChange)
+ , window(window)
+ , requestedGeometry(window->handle() ? window->handle()->QPlatformWindow::geometry() : QRect())
+ , newGeometry(newGeometry)
{
- QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window), QHighDpi::fromNativePixels(oldRect, window));
+}
+
+QT_DEFINE_QPA_EVENT_HANDLER(void, handleGeometryChange, QWindow *window, const QRect &newRect)
+{
+ Q_ASSERT(window);
+ QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(window, QHighDpi::fromNativePixels(newRect, window));
+ if (window->handle()) {
+ // Persist the new geometry so that QWindow::geometry() can be queried in the resize event
+ window->handle()->QPlatformWindow::setGeometry(newRect);
+ // FIXME: This does not work during platform window creation, where the QWindow does not
+ // have its handle set up yet. Platforms that deliver events during window creation need
+ // to handle the persistence manually, e.g. by overriding geometry().
+ }
QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e);
}
@@ -297,6 +310,23 @@ QWindowSystemInterfacePrivate::ExposeEvent::ExposeEvent(QWindow *window, const Q
{
}
+/*! \internal
+ Handles an expose event.
+
+ The platform plugin sends expose events when an area of the window
+ is invalidated or window exposure changes. \a region is in window
+ local coordinates. An empty region indicates that the window is
+ obscured, but note that the exposed property of the QWindow will be set
+ based on what QPlatformWindow::isExposed() returns at the time of this call,
+ not based on what the region is. // FIXME: this should probably be fixed.
+
+ The platform plugin may omit sending expose events (or send obscure
+ events) for windows that are on screen but where the client area is
+ completely covered by other windows or otherwise not visible. Expose
+ event consumers can then use this to disable updates for such windows.
+ This is required behavior on platforms where OpenGL swapbuffers stops
+ blocking for obscured windows (like macOS).
+*/
QT_DEFINE_QPA_EVENT_HANDLER(void, handleExposeEvent, QWindow *window, const QRegion &region)
{
QWindowSystemInterfacePrivate::ExposeEvent *e =
@@ -452,9 +482,13 @@ QWindowSystemInterfacePrivate::WheelEvent::WheelEvent(QWindow *window, ulong tim
{
}
+#if QT_DEPRECATED_SINCE(5, 10)
void QWindowSystemInterface::handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods) {
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
handleWheelEvent(window, time, local, global, d, o, mods);
+QT_WARNING_POP
}
void QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods)
@@ -462,6 +496,7 @@ void QWindowSystemInterface::handleWheelEvent(QWindow *window, ulong timestamp,
QPoint point = (o == Qt::Vertical) ? QPoint(0, d) : QPoint(d, 0);
handleWheelEvent(window, timestamp, local, global, QPoint(), point, mods);
}
+#endif // QT_DEPRECATED_SINCE(5, 10)
void QWindowSystemInterface::handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, QPoint pixelDelta, QPoint angleDelta, Qt::KeyboardModifiers mods, Qt::ScrollPhase phase, Qt::MouseEventSource source)
{
@@ -775,6 +810,7 @@ void QWindowSystemInterface::handleTabletEvent(QWindow *window, const QPointF &l
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
}
+#if QT_DEPRECATED_SINCE(5, 10)
void QWindowSystemInterface::handleTabletEvent(QWindow *window, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
int device, int pointerType, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
@@ -792,6 +828,7 @@ void QWindowSystemInterface::handleTabletEvent(QWindow *window, bool down, const
handleTabletEvent(window, local, global, device, pointerType, (down ? Qt::LeftButton : Qt::NoButton), pressure,
xTilt, yTilt, tangentialPressure, rotation, z, uid, modifiers);
}
+#endif // QT_DEPRECATED_SINCE(5, 10)
void QWindowSystemInterface::handleTabletEnterProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid)
{
@@ -820,28 +857,28 @@ void QWindowSystemInterface::handleTabletLeaveProximityEvent(int device, int poi
}
#ifndef QT_NO_GESTURES
-void QWindowSystemInterface::handleGestureEvent(QWindow *window, ulong timestamp, Qt::NativeGestureType type,
+void QWindowSystemInterface::handleGestureEvent(QWindow *window, QTouchDevice *device, ulong timestamp, Qt::NativeGestureType type,
QPointF &local, QPointF &global)
{
QWindowSystemInterfacePrivate::GestureEvent *e =
- new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, local, global);
+ new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, local, global);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
-void QWindowSystemInterface::handleGestureEventWithRealValue(QWindow *window, ulong timestamp, Qt::NativeGestureType type,
+void QWindowSystemInterface::handleGestureEventWithRealValue(QWindow *window, QTouchDevice *device, ulong timestamp, Qt::NativeGestureType type,
qreal value, QPointF &local, QPointF &global)
{
QWindowSystemInterfacePrivate::GestureEvent *e =
- new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, local, global);
+ new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, local, global);
e->realValue = value;
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
-void QWindowSystemInterface::handleGestureEventWithSequenceIdAndValue(QWindow *window, ulong timestamp, Qt::NativeGestureType type,
+void QWindowSystemInterface::handleGestureEventWithSequenceIdAndValue(QWindow *window, QTouchDevice *device, ulong timestamp, Qt::NativeGestureType type,
ulong sequenceId, quint64 value, QPointF &local, QPointF &global)
{
QWindowSystemInterfacePrivate::GestureEvent *e =
- new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, local, global);
+ new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, device, local, global);
e->sequenceId = sequenceId;
e->intValue = value;
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index fb428233ab..bd6416cc95 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -121,9 +121,10 @@ public:
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized,
bool inverted = false);
- // Wheel event compatibility functions. Will be removed: do not use.
- static void handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
- static void handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
+#if QT_DEPRECATED_SINCE(5, 10)
+ QT_DEPRECATED static void handleWheelEvent(QWindow *window, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
+ QT_DEPRECATED static void handleWheelEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier);
+#endif
struct TouchPoint {
TouchPoint() : id(0), uniqueId(-1), pressure(0), rotation(0), state(Qt::TouchPointStationary) { }
@@ -159,7 +160,7 @@ public:
// rect is relative to parent
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleGeometryChange(QWindow *window, const QRect &newRect, const QRect &oldRect = QRect());
+ static void handleGeometryChange(QWindow *window, const QRect &newRect);
// region is in local coordinates, do not confuse with geometry which is parent-relative
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
@@ -176,7 +177,7 @@ public:
static void handleWindowActivated(QWindow *window, Qt::FocusReason r = Qt::OtherFocusReason);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
- static void handleWindowStateChanged(QWindow *window, Qt::WindowState newState, int oldState = -1);
+ static void handleWindowStateChanged(QWindow *window, Qt::WindowStates newState, int oldState = -1);
static void handleWindowScreenChanged(QWindow *window, QScreen *newScreen);
template<typename Delivery = QWindowSystemInterface::DefaultDelivery>
@@ -212,25 +213,27 @@ public:
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure, int xTilt, int yTilt,
qreal tangentialPressure, qreal rotation, int z, qint64 uid,
Qt::KeyboardModifiers modifiers = Qt::NoModifier);
- static void handleTabletEvent(QWindow *window, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
- int device, int pointerType, qreal pressure, int xTilt, int yTilt,
- qreal tangentialPressure, qreal rotation, int z, qint64 uid,
- Qt::KeyboardModifiers modifiers = Qt::NoModifier); // ### remove in Qt 6
- static void handleTabletEvent(QWindow *window, bool down, const QPointF &local, const QPointF &global,
- int device, int pointerType, qreal pressure, int xTilt, int yTilt,
- qreal tangentialPressure, qreal rotation, int z, qint64 uid,
- Qt::KeyboardModifiers modifiers = Qt::NoModifier); // ### remove in Qt 6
+#if QT_DEPRECATED_SINCE(5, 10)
+ QT_DEPRECATED static void handleTabletEvent(QWindow *window, ulong timestamp, bool down, const QPointF &local, const QPointF &global,
+ int device, int pointerType, qreal pressure, int xTilt, int yTilt,
+ qreal tangentialPressure, qreal rotation, int z, qint64 uid,
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier);
+ QT_DEPRECATED static void handleTabletEvent(QWindow *window, bool down, const QPointF &local, const QPointF &global,
+ int device, int pointerType, qreal pressure, int xTilt, int yTilt,
+ qreal tangentialPressure, qreal rotation, int z, qint64 uid,
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier);
+#endif
static void handleTabletEnterProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid);
static void handleTabletEnterProximityEvent(int device, int pointerType, qint64 uid);
static void handleTabletLeaveProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid);
static void handleTabletLeaveProximityEvent(int device, int pointerType, qint64 uid);
#ifndef QT_NO_GESTURES
- static void handleGestureEvent(QWindow *window, ulong timestamp, Qt::NativeGestureType type,
+ static void handleGestureEvent(QWindow *window, QTouchDevice *device, ulong timestamp, Qt::NativeGestureType type,
QPointF &local, QPointF &global);
- static void handleGestureEventWithRealValue(QWindow *window, ulong timestamp, Qt::NativeGestureType type,
+ static void handleGestureEventWithRealValue(QWindow *window, QTouchDevice *device, ulong timestamp, Qt::NativeGestureType type,
qreal value, QPointF &local, QPointF &global);
- static void handleGestureEventWithSequenceIdAndValue(QWindow *window, ulong timestamp,Qt::NativeGestureType type,
+ static void handleGestureEventWithSequenceIdAndValue(QWindow *window, QTouchDevice *device, ulong timestamp,Qt::NativeGestureType type,
ulong sequenceId, quint64 value, QPointF &local, QPointF &global);
#endif // QT_NO_GESTURES
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index 5b41ccc3a5..f781d6e3b8 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -132,12 +132,10 @@ public:
class GeometryChangeEvent : public WindowSystemEvent {
public:
- GeometryChangeEvent(QWindow *window, const QRect &newGeometry, const QRect &oldGeometry)
- : WindowSystemEvent(GeometryChange), window(window), newGeometry(newGeometry), oldGeometry(oldGeometry)
- { }
+ GeometryChangeEvent(QWindow *window, const QRect &newGeometry);
QPointer<QWindow> window;
+ QRect requestedGeometry;
QRect newGeometry;
- QRect oldGeometry;
};
class EnterEvent : public WindowSystemEvent {
@@ -169,13 +167,13 @@ public:
class WindowStateChangedEvent : public WindowSystemEvent {
public:
- WindowStateChangedEvent(QWindow *_window, Qt::WindowState _newState, Qt::WindowState _oldState)
+ WindowStateChangedEvent(QWindow *_window, Qt::WindowStates _newState, Qt::WindowStates _oldState)
: WindowSystemEvent(WindowStateChanged), window(_window), newState(_newState), oldState(_oldState)
{ }
QPointer<QWindow> window;
- Qt::WindowState newState;
- Qt::WindowState oldState;
+ Qt::WindowStates newState;
+ Qt::WindowStates oldState;
};
class WindowScreenChangedEvent : public WindowSystemEvent {
@@ -433,9 +431,9 @@ public:
#ifndef QT_NO_GESTURES
class GestureEvent : public InputEvent {
public:
- GestureEvent(QWindow *window, ulong time, Qt::NativeGestureType type, QPointF pos, QPointF globalPos)
+ GestureEvent(QWindow *window, ulong time, Qt::NativeGestureType type, QTouchDevice *dev, QPointF pos, QPointF globalPos)
: InputEvent(window, time, Gesture, Qt::NoModifier), type(type), pos(pos), globalPos(globalPos),
- realValue(0), sequenceId(0), intValue(0) { }
+ realValue(0), sequenceId(0), intValue(0), device(dev) { }
Qt::NativeGestureType type;
QPointF pos;
QPointF globalPos;
@@ -444,6 +442,7 @@ public:
// Windows
ulong sequenceId;
quint64 intValue;
+ QTouchDevice *device;
};
#endif
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
index 6b18e1ab03..d016f07522 100644
--- a/src/gui/math3d/qmatrix4x4.cpp
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -1128,7 +1128,7 @@ void QMatrix4x4::rotate(float angle, float x, float y, float z)
s = 0.0f;
c = -1.0f;
} else {
- float a = angle * M_PI / 180.0f;
+ float a = qDegreesToRadians(angle);
c = std::cos(a);
s = std::sin(a);
}
@@ -1237,7 +1237,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
s = 0.0f;
c = -1.0f;
} else {
- float a = angle * M_PI / 180.0f;
+ float a = qDegreesToRadians(angle);
c = std::cos(a);
s = std::sin(a);
}
@@ -1496,7 +1496,7 @@ void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearP
// Construct the projection.
QMatrix4x4 m(1);
- float radians = (verticalAngle / 2.0f) * M_PI / 180.0f;
+ float radians = qDegreesToRadians(verticalAngle / 2.0f);
float sine = std::sin(radians);
if (sine == 0.0f)
return;
diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h
index 4db96d07c0..97df11a8bd 100644
--- a/src/gui/math3d/qmatrix4x4.h
+++ b/src/gui/math3d/qmatrix4x4.h
@@ -859,8 +859,8 @@ inline QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
{
float xin, yin;
float x, y, w;
- xin = point.x();
- yin = point.y();
+ xin = float(point.x());
+ yin = float(point.y());
x = xin * matrix.m[0][0] +
yin * matrix.m[0][1] +
matrix.m[0][3];
@@ -1094,7 +1094,7 @@ inline float *QMatrix4x4::data()
inline void QMatrix4x4::viewport(const QRectF &rect)
{
- viewport(rect.x(), rect.y(), rect.width(), rect.height());
+ viewport(float(rect.x()), float(rect.y()), float(rect.width()), float(rect.height()));
}
QT_WARNING_POP
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index e3262c8830..fe1b0425a8 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -408,7 +408,7 @@ QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, float angle)
// http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56
// We normalize the result just in case the values are close
// to zero, as suggested in the above FAQ.
- float a = (angle / 2.0f) * M_PI / 180.0f;
+ float a = qDegreesToRadians(angle / 2.0f);
float s = std::sin(a);
float c = std::cos(a);
QVector3D ax = axis.normalized();
@@ -467,7 +467,7 @@ QQuaternion QQuaternion::fromAxisAndAngle
y /= length;
z /= length;
}
- float a = (angle / 2.0f) * M_PI / 180.0f;
+ float a = qDegreesToRadians(angle / 2.0f);
float s = std::sin(a);
float c = std::cos(a);
return QQuaternion(c, x * s, y * s, z * s).normalized();
diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h
index 7f7f89db4d..cd0d746e55 100644
--- a/src/gui/math3d/qquaternion.h
+++ b/src/gui/math3d/qquaternion.h
@@ -210,8 +210,8 @@ inline QQuaternion QQuaternion::inverted() const
double(yp) * double(yp) +
double(zp) * double(zp);
if (!qFuzzyIsNull(len))
- return QQuaternion(double(wp) / len, double(-xp) / len,
- double(-yp) / len, double(-zp) / len);
+ return QQuaternion(float(double(wp) / len), float(double(-xp) / len),
+ float(double(-yp) / len), float(double(-zp) / len));
return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
}
diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h
index 5e0394b998..2af5132665 100644
--- a/src/gui/math3d/qvector2d.h
+++ b/src/gui/math3d/qvector2d.h
@@ -137,7 +137,7 @@ Q_DECL_CONSTEXPR inline QVector2D::QVector2D(float xpos, float ypos) : xp(xpos),
Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPoint& point) : xp(point.x()), yp(point.y()) {}
-Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPointF& point) : xp(point.x()), yp(point.y()) {}
+Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())) {}
inline bool QVector2D::isNull() const
{
diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h
index a728fd76bf..f3e8c976b7 100644
--- a/src/gui/math3d/qvector3d.h
+++ b/src/gui/math3d/qvector3d.h
@@ -154,7 +154,7 @@ Q_DECL_CONSTEXPR inline QVector3D::QVector3D() : xp(0.0f), yp(0.0f), zp(0.0f) {}
Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f) {}
-Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f) {}
+Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())), zp(0.0f) {}
inline bool QVector3D::isNull() const
{
diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h
index be373aa806..3f14b41e8e 100644
--- a/src/gui/math3d/qvector4d.h
+++ b/src/gui/math3d/qvector4d.h
@@ -146,7 +146,7 @@ Q_DECL_CONSTEXPR inline QVector4D::QVector4D(float xpos, float ypos, float zpos,
Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {}
-Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPointF& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {}
+Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())), zp(0.0f), wp(0.0f) {}
inline bool QVector4D::isNull() const
{
diff --git a/src/gui/opengl/qopengl.h b/src/gui/opengl/qopengl.h
index b5df68a3aa..f6c350ba0b 100644
--- a/src/gui/opengl/qopengl.h
+++ b/src/gui/opengl/qopengl.h
@@ -101,7 +101,9 @@ typedef void* GLeglImageOES;
# define QGL_TEMP_GLEXT_PROTO
# endif
-# if defined(QT_OPENGL_ES_3_1)
+# if defined(QT_OPENGL_ES_3_2)
+# include <GLES3/gl32.h>
+# elif defined(QT_OPENGL_ES_3_1)
# include <GLES3/gl31.h>
# elif defined(QT_OPENGL_ES_3)
# include <GLES3/gl3.h>
diff --git a/src/gui/opengl/qopenglextrafunctions.h b/src/gui/opengl/qopenglextrafunctions.h
index 1b36068588..81716fb8d3 100644
--- a/src/gui/opengl/qopenglextrafunctions.h
+++ b/src/gui/opengl/qopenglextrafunctions.h
@@ -52,6 +52,11 @@
#undef MemoryBarrier
#endif
+// GLES build without having included gl32.h -> GLDEBUGPROC is still need for the protos, define it here
+#if defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_ES_3_2)
+typedef void (QOPENGLF_APIENTRYP *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam);
+#endif
+
QT_BEGIN_NAMESPACE
class QOpenGLExtraFunctionsPrivate;
@@ -230,6 +235,50 @@ class QOpenGLExtraFunctionsPrivate;
#undef glVertexAttribBinding
#undef glVertexBindingDivisor
+#undef glBlendBarrier
+#undef glCopyImageSubData
+#undef glDebugMessageControl
+#undef glDebugMessageInsert
+#undef glDebugMessageCallback
+#undef glGetDebugMessageLog
+#undef glPushDebugGroup
+#undef glPopDebugGroup
+#undef glObjectLabel
+#undef glGetObjectLabel
+#undef glGetObjectPtrLabel
+#undef glGetPointerv
+#undef glEnablei
+#undef glDisablei
+#undef glBlendEquationi
+#undef glBlendEquationSeparatei
+#undef glBlendFunci
+#undef glBlendFuncSeparatei
+#undef glColorMaski
+#undef glIsEnabledi
+#undef glDrawElementsBaseVertex
+#undef glDrawRangeElementsBaseVertex
+#undef glDrawElementsInstancedBaseVertex
+#undef glFrameBufferTexture
+#undef glPrimitiveBoundingBox
+#undef glGetGraphicsResetStatus
+#undef glReadnPixels
+#undef glGetnUniformfv
+#undef glGetnUniformiv
+#undef glGetnUniformuiv
+#undef glMinSampleShading
+#undef glPatchParameteri
+#undef glTexParameterIiv
+#undef glTexParameterIuiv
+#undef glGetTexParameterIiv
+#undef glGetTexParameterIuiv
+#undef glSamplerParameterIiv
+#undef glSamplerParameterIuiv
+#undef glGetSamplerParameterIiv
+#undef glGetSamplerParameterIuiv
+#undef glTexBuffer
+#undef glTexBufferRange
+#undef glTexStorage3DMultisample
+
class Q_GUI_EXPORT QOpenGLExtraFunctions : public QOpenGLFunctions
{
Q_DECLARE_PRIVATE(QOpenGLExtraFunctions)
@@ -415,6 +464,52 @@ public:
void glVertexAttribBinding(GLuint attribindex, GLuint bindingindex);
void glVertexBindingDivisor(GLuint bindingindex, GLuint divisor);
+ // GLES 3.2
+ void glBlendBarrier(void);
+ void glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+ void glDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+ void glDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+ void glDebugMessageCallback(GLDEBUGPROC callback, const void *userParam);
+ GLuint glGetDebugMessageLog(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+ void glPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar *message);
+ void glPopDebugGroup(void);
+ void glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+ void glGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+ void glObjectPtrLabel(const void *ptr, GLsizei length, const GLchar *label);
+ void glGetObjectPtrLabel(const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+ void glGetPointerv(GLenum pname, void **params);
+ void glEnablei(GLenum target, GLuint index);
+ void glDisablei(GLenum target, GLuint index);
+ void glBlendEquationi(GLuint buf, GLenum mode);
+ void glBlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+ void glBlendFunci(GLuint buf, GLenum src, GLenum dst);
+ void glBlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+ void glColorMaski(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+ GLboolean glIsEnabledi(GLenum target, GLuint index);
+ void glDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+ void glDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices, GLint basevertex);
+ void glDrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount, GLint basevertex);
+ void glFramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level);
+ void glPrimitiveBoundingBox(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+ GLenum glGetGraphicsResetStatus(void);
+ void glReadnPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+ void glGetnUniformfv(GLuint program, GLint location, GLsizei bufSize, GLfloat *params);
+ void glGetnUniformiv(GLuint program, GLint location, GLsizei bufSize, GLint *params);
+ void glGetnUniformuiv(GLuint program, GLint location, GLsizei bufSize, GLuint *params);
+ void glMinSampleShading(GLfloat value);
+ void glPatchParameteri(GLenum pname, GLint value);
+ void glTexParameterIiv(GLenum target, GLenum pname, const GLint *params);
+ void glTexParameterIuiv(GLenum target, GLenum pname, const GLuint *params);
+ void glGetTexParameterIiv(GLenum target, GLenum pname, GLint *params);
+ void glGetTexParameterIuiv(GLenum target, GLenum pname, GLuint *params);
+ void glSamplerParameterIiv(GLuint sampler, GLenum pname, const GLint *param);
+ void glSamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint *param);
+ void glGetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint *params);
+ void glGetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint *params);
+ void glTexBuffer(GLenum target, GLenum internalformat, GLuint buffer);
+ void glTexBufferRange(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+ void glTexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+
private:
static bool isInitialized(const QOpenGLExtraFunctionsPrivate *d) { return d != Q_NULLPTR; }
};
@@ -615,6 +710,50 @@ public:
F(void, VertexAttribIFormat, (GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset)) \
F(void, VertexAttribBinding, (GLuint attribindex, GLuint bindingindex)) \
F(void, VertexBindingDivisor, (GLuint bindingindex, GLuint divisor)) \
+ F(void, BlendBarrier, (void)) \
+ F(void, BlendEquationSeparatei, (GLuint buf, GLenum modeRGB, GLenum modeAlpha)) \
+ F(void, BlendEquationi, (GLuint buf, GLenum mode)) \
+ F(void, BlendFuncSeparatei, (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)) \
+ F(void, BlendFunci, (GLuint buf, GLenum src, GLenum dst)) \
+ F(void, ColorMaski, (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a)) \
+ F(void, CopyImageSubData, (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)) \
+ F(void, DebugMessageCallback, (GLDEBUGPROC callback, const void * userParam)) \
+ F(void, DebugMessageControl, (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled)) \
+ F(void, DebugMessageInsert, (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf)) \
+ F(void, Disablei, (GLenum target, GLuint index)) \
+ F(void, DrawElementsBaseVertex, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex)) \
+ F(void, DrawElementsInstancedBaseVertex, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex)) \
+ F(void, DrawRangeElementsBaseVertex, (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex)) \
+ F(void, Enablei, (GLenum target, GLuint index)) \
+ F(void, FramebufferTexture, (GLenum target, GLenum attachment, GLuint texture, GLint level)) \
+ F(GLuint, GetDebugMessageLog, (GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog)) \
+ F(GLenum, GetGraphicsResetStatus, (void)) \
+ F(void, GetObjectLabel, (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label)) \
+ F(void, GetObjectPtrLabel, (const void * ptr, GLsizei bufSize, GLsizei* length, GLchar* label)) \
+ F(void, GetPointerv, (GLenum pname, void ** params)) \
+ F(void, GetSamplerParameterIiv, (GLuint sampler, GLenum pname, GLint* params)) \
+ F(void, GetSamplerParameterIuiv, (GLuint sampler, GLenum pname, GLuint* params)) \
+ F(void, GetTexParameterIiv, (GLenum target, GLenum pname, GLint* params)) \
+ F(void, GetTexParameterIuiv, (GLenum target, GLenum pname, GLuint* params)) \
+ F(void, GetnUniformfv, (GLuint program, GLint location, GLsizei bufSize, GLfloat* params)) \
+ F(void, GetnUniformiv, (GLuint program, GLint location, GLsizei bufSize, GLint* params)) \
+ F(void, GetnUniformuiv, (GLuint program, GLint location, GLsizei bufSize, GLuint* params)) \
+ F(GLboolean, IsEnabledi, (GLenum target, GLuint index)) \
+ F(void, MinSampleShading, (GLfloat value)) \
+ F(void, ObjectLabel, (GLenum identifier, GLuint name, GLsizei length, const GLchar * label)) \
+ F(void, ObjectPtrLabel, (const void * ptr, GLsizei length, const GLchar * label)) \
+ F(void, PatchParameteri, (GLenum pname, GLint value)) \
+ F(void, PopDebugGroup, (void)) \
+ F(void, PrimitiveBoundingBox, (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW)) \
+ F(void, PushDebugGroup, (GLenum source, GLuint id, GLsizei length, const GLchar * message)) \
+ F(void, ReadnPixels, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data)) \
+ F(void, SamplerParameterIiv, (GLuint sampler, GLenum pname, const GLint * param)) \
+ F(void, SamplerParameterIuiv, (GLuint sampler, GLenum pname, const GLuint * param)) \
+ F(void, TexBuffer, (GLenum target, GLenum internalformat, GLuint buffer)) \
+ F(void, TexBufferRange, (GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size)) \
+ F(void, TexParameterIiv, (GLenum target, GLenum pname, const GLint * params)) \
+ F(void, TexParameterIuiv, (GLenum target, GLenum pname, const GLuint * params)) \
+ F(void, TexStorage3DMultisample, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)) \
QT_OPENGL_DECLARE(QT_OPENGL_EXTRA_FUNCTIONS)
};
@@ -2013,6 +2152,363 @@ inline void QOpenGLExtraFunctions::glVertexBindingDivisor(GLuint bindingindex, G
Q_OPENGL_FUNCTIONS_DEBUG
}
+// GLES 3.2
+
+inline void QOpenGLExtraFunctions::glBlendBarrier()
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.BlendBarrier();
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glBlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.BlendEquationSeparatei(buf, modeRGB, modeAlpha);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glBlendEquationi(GLuint buf, GLenum mode)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.BlendEquationi(buf, mode);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glBlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.BlendFuncSeparatei(buf, srcRGB, dstRGB, srcAlpha, dstAlpha);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glBlendFunci(GLuint buf, GLenum src, GLenum dst)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.BlendFunci(buf, src, dst);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glColorMaski(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.ColorMaski(index, r, g, b, a);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.CopyImageSubData(srcName, srcTarget, srcLevel, srcX, srcY, srcZ, dstName, dstTarget, dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight, srcDepth);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glDebugMessageCallback(GLDEBUGPROC callback, const void * userParam)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.DebugMessageCallback(callback, userParam);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.DebugMessageControl(source, type, severity, count, ids, enabled);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.DebugMessageInsert(source, type, id, severity, length, buf);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glDisablei(GLenum target, GLuint index)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.Disablei(target, index);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.DrawElementsBaseVertex(mode, count, type, indices, basevertex);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glDrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.DrawElementsInstancedBaseVertex(mode, count, type, indices, instancecount, basevertex);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.DrawRangeElementsBaseVertex(mode, start, end, count, type, indices, basevertex);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glEnablei(GLenum target, GLuint index)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.Enablei(target, index);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glFramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.FramebufferTexture(target, attachment, texture, level);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline GLuint QOpenGLExtraFunctions::glGetDebugMessageLog(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ GLuint result = d->f.GetDebugMessageLog(count, bufSize, sources, types, ids, severities, lengths, messageLog);
+ Q_OPENGL_FUNCTIONS_DEBUG
+ return result;
+}
+
+inline GLenum QOpenGLExtraFunctions::glGetGraphicsResetStatus()
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ GLenum result = d->f.GetGraphicsResetStatus();
+ Q_OPENGL_FUNCTIONS_DEBUG
+ return result;
+}
+
+inline void QOpenGLExtraFunctions::glGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetObjectLabel(identifier, name, bufSize, length, label);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetObjectPtrLabel(const void * ptr, GLsizei bufSize, GLsizei* length, GLchar* label)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetObjectPtrLabel(ptr, bufSize, length, label);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetPointerv(GLenum pname, void ** params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetPointerv(pname, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetSamplerParameterIiv(sampler, pname, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetSamplerParameterIuiv(sampler, pname, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetTexParameterIiv(GLenum target, GLenum pname, GLint* params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetTexParameterIiv(target, pname, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetTexParameterIuiv(GLenum target, GLenum pname, GLuint* params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetTexParameterIuiv(target, pname, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetnUniformfv(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetnUniformfv(program, location, bufSize, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetnUniformiv(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetnUniformiv(program, location, bufSize, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glGetnUniformuiv(GLuint program, GLint location, GLsizei bufSize, GLuint* params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.GetnUniformuiv(program, location, bufSize, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline GLboolean QOpenGLExtraFunctions::glIsEnabledi(GLenum target, GLuint index)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ GLboolean result = d->f.IsEnabledi(target, index);
+ Q_OPENGL_FUNCTIONS_DEBUG
+ return result;
+}
+
+inline void QOpenGLExtraFunctions::glMinSampleShading(GLfloat value)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.MinSampleShading(value);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar * label)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.ObjectLabel(identifier, name, length, label);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glObjectPtrLabel(const void * ptr, GLsizei length, const GLchar * label)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.ObjectPtrLabel(ptr, length, label);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glPatchParameteri(GLenum pname, GLint value)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.PatchParameteri(pname, value);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glPopDebugGroup()
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.PopDebugGroup();
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glPrimitiveBoundingBox(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.PrimitiveBoundingBox(minX, minY, minZ, minW, maxX, maxY, maxZ, maxW);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar * message)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.PushDebugGroup(source, id, length, message);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glReadnPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.ReadnPixels(x, y, width, height, format, type, bufSize, data);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glSamplerParameterIiv(GLuint sampler, GLenum pname, const GLint * param)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.SamplerParameterIiv(sampler, pname, param);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glSamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint * param)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.SamplerParameterIuiv(sampler, pname, param);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glTexBuffer(GLenum target, GLenum internalformat, GLuint buffer)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.TexBuffer(target, internalformat, buffer);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glTexBufferRange(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.TexBufferRange(target, internalformat, buffer, offset, size);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glTexParameterIiv(GLenum target, GLenum pname, const GLint * params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.TexParameterIiv(target, pname, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glTexParameterIuiv(GLenum target, GLenum pname, const GLuint * params)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.TexParameterIuiv(target, pname, params);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
+inline void QOpenGLExtraFunctions::glTexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)
+{
+ Q_D(QOpenGLExtraFunctions);
+ Q_ASSERT(QOpenGLExtraFunctions::isInitialized(d));
+ d->f.TexStorage3DMultisample(target, samples, internalformat, width, height, depth, fixedsamplelocations);
+ Q_OPENGL_FUNCTIONS_DEBUG
+}
+
QT_END_NAMESPACE
#undef QT_OPENGL_DECLARE_FUNCTIONS
diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp
index e724efab37..f2bc357c3a 100644
--- a/src/gui/opengl/qopenglfunctions.cpp
+++ b/src/gui/opengl/qopenglfunctions.cpp
@@ -2213,17 +2213,17 @@ QT_OPENGL_IMPLEMENT(QOpenGLFunctionsPrivate, QT_OPENGL_FUNCTIONS)
/*!
\class QOpenGLExtraFunctions
- \brief The QOpenGLExtraFunctions class provides cross-platform access to the OpenGL ES 3.0 and 3.1 API.
+ \brief The QOpenGLExtraFunctions class provides cross-platform access to the OpenGL ES 3.0, 3.1 and 3.2 API.
\since 5.6
\ingroup painting-3D
\inmodule QtGui
- This subclass of QOpenGLFunctions includes the OpenGL ES 3.0 and 3.1
- functions. These will only work when an OpenGL ES 3.0 or 3.1 context, or an
+ This subclass of QOpenGLFunctions includes the OpenGL ES 3.0, 3.1 and 3.2
+ functions. These will only work when an OpenGL ES 3.x context, or an
OpenGL context of a version containing the functions in question either in
- core or as extension, is in use. This allows developing GLES 3.0 and 3.1
+ core or as extension, is in use. This allows developing GLES 3.x
applications in a cross-platform manner: development can happen on a desktop
- platform with OpenGL 3.x or 4.x, deploying to a real GLES 3.1 device later
+ platform with OpenGL 3.x or 4.x, deploying to a true GLES 3.x device later
on will require no or minimal changes to the application.
\note This class is different from the versioned OpenGL wrappers, for
@@ -4469,6 +4469,578 @@ QT_OPENGL_IMPLEMENT(QOpenGLFunctionsPrivate, QT_OPENGL_FUNCTIONS)
*/
/*!
+ \fn void QOpenGLExtraFunctions::glBlendBarrier(void)
+
+ Convenience function that calls glBlendBarrier().
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glBlendBarrier.xml}{glBlendBarrier()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glBlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeAlpha)
+
+ Convenience function that calls glBlendEquationSeparatei(\a buf, \a modeRGB, \a modeAlpha).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glBlendEquationSeparatei.xml}{glBlendEquationSeparatei()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glBlendEquationi(GLuint buf, GLenum mode)
+
+ Convenience function that calls glBlendEquationi(\a buf, \a mode).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glBlendEquationi.xml}{glBlendEquationi()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glBlendFuncSeparatei(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+
+ Convenience function that calls glBlendFuncSeparatei(\a buf, \a srcRGB, \a dstRGB, \a srcAlpha, \a dstAlpha).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glBlendFuncSeparatei.xml}{glBlendFuncSeparatei()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glBlendFunci(GLuint buf, GLenum src, GLenum dst)
+
+ Convenience function that calls glBlendFunci(\a buf, \a src, \a dst).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glBlendFunci.xml}{glBlendFunci()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glColorMaski(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a)
+
+ Convenience function that calls glColorMaski(\a index, \a r, \a g, \a b, \a a).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glColorMaski.xml}{glColorMaski()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth)
+
+ Convenience function that calls glCopyImageSubData(\a srcName, \a srcTarget, \a srcLevel, \a srcX, \a srcY, \a srcZ, \a dstName, \a dstTarget, \a dstLevel, \a dstX, \a dstY, \a dstZ, \a srcWidth, \a srcHeight, \a srcDepth).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glCopyImageSubData.xml}{glCopyImageSubData()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glDebugMessageCallback(GLDEBUGPROC callback, const void * userParam)
+
+ Convenience function that calls glDebugMessageCallback(\a callback, \a userParam).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glDebugMessageCallback.xml}{glDebugMessageCallback()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glDebugMessageControl(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled)
+
+ Convenience function that calls glDebugMessageControl(\a source, \a type, \a severity, \a count, \a ids, \a enabled).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glDebugMessageControl.xml}{glDebugMessageContro()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glDebugMessageInsert(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf)
+
+ Convenience function that calls glDebugMessageInsert(\a source, \a type, \a id, \a severity, \a length, \a buf).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glDebugMessageInsert.xml}{glDebugMessageInsert()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glDisablei(GLenum target, GLuint index)
+
+ Convenience function that calls glDisablei(\a target, \a index).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glDisablei.xml}{glDisablei()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glDrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, const void * indices, GLint basevertex)
+
+ Convenience function that calls glDrawElementsBaseVertex(\a mode, \a count, \a type, \a indices, \a basevertex).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glDrawElementsBaseVertex.xml}{glDrawElementsBaseVerte()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glDrawElementsInstancedBaseVertex(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount, GLint basevertex)
+
+ Convenience function that calls glDrawElementsInstancedBaseVertex(\a mode, \a count, \a type, \a indices, \a instancecount, \a basevertex).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glDrawElementsInstancedBaseVertex.xml}{glDrawElementsInstancedBaseVerte()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glDrawRangeElementsBaseVertex(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices, GLint basevertex)
+
+ Convenience function that calls glDrawRangeElementsBaseVertex(\a mode, \a start, \a end, \a count, \a type, \a indices, \a basevertex).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glDrawRangeElementsBaseVertex.xml}{glDrawRangeElementsBaseVerte()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glEnablei(GLenum target, GLuint index)
+
+ Convenience function that calls glEnablei(\a target, \a index).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glEnablei.xml}{glEnablei()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glFramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level)
+
+ Convenience function that calls glFramebufferTexture(\a target, \a attachment, \a texture, \a level).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glFramebufferTexture.xml}{glFramebufferTexture()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetDebugMessageLog(GLuint count, GLsizei bufSize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog)
+
+ Convenience function that calls glGetDebugMessageLog(\a count, \a bufSize, \a sources, \a types, \a ids, \a severities, \a lengths, \a messageLog).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetDebugMessageLog.xml}{glGetDebugMessageLog()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetGraphicsResetStatus(void)
+
+ Convenience function that calls glGetGraphicsResetStatus().
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetGraphicsResetStatus.xml}{glGetGraphicsResetStatus()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetObjectLabel(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar* label)
+
+ Convenience function that calls glGetObjectLabel(\a identifier, \a name, \a bufSize, \a length, \a label).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetObjectLabel.xml}{glGetObjectLabe()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetObjectPtrLabel(const void * ptr, GLsizei bufSize, GLsizei* length, GLchar* label)
+
+ Convenience function that calls glGetObjectPtrLabel(\a ptr, \a bufSize, \a length, \a label).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetObjectPtrLabel.xml}{glGetObjectPtrLabe()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetPointerv(GLenum pname, void ** params)
+
+ Convenience function that calls glGetPointerv(\a pname, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetPointerv.xml}{glGetPointerv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetSamplerParameterIiv(GLuint sampler, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetSamplerParameterIiv(\a sampler, \a pname, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetSamplerParameterIiv.xml}{glGetSamplerParameterIiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetSamplerParameterIuiv(GLuint sampler, GLenum pname, GLuint* params)
+
+ Convenience function that calls glGetSamplerParameterIuiv(\a sampler, \a pname, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetSamplerParameterIuiv.xml}{glGetSamplerParameterIuiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetTexParameterIiv(GLenum target, GLenum pname, GLint* params)
+
+ Convenience function that calls glGetTexParameterIiv(\a target, \a pname, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetTexParameterIiv.xml}{glGetTexParameterIiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetTexParameterIuiv(GLenum target, GLenum pname, GLuint* params)
+
+ Convenience function that calls glGetTexParameterIuiv(\a target, \a pname, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetTexParameterIuiv.xml}{glGetTexParameterIuiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetnUniformfv(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
+
+ Convenience function that calls glGetnUniformfv(\a program, \a location, \a bufSize, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetnUniformfv.xml}{glGetnUniformfv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetnUniformiv(GLuint program, GLint location, GLsizei bufSize, GLint* params)
+
+ Convenience function that calls glGetnUniformiv(\a program, \a location, \a bufSize, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetnUniformiv.xml}{glGetnUniformiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glGetnUniformuiv(GLuint program, GLint location, GLsizei bufSize, GLuint* params)
+
+ Convenience function that calls glGetnUniformuiv(\a program, \a location, \a bufSize, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glGetnUniformuiv.xml}{glGetnUniformuiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glIsEnabledi(GLenum target, GLuint index)
+
+ Convenience function that calls glIsEnabledi(\a target, \a index).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glIsEnabledi.xml}{glIsEnabledi()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glMinSampleShading(GLfloat value)
+
+ Convenience function that calls glMinSampleShading(\a value).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glMinSampleShading.xml}{glMinSampleShading()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glObjectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar * label)
+
+ Convenience function that calls glObjectLabel(\a identifier, \a name, \a length, \a label).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glObjectLabel.xml}{glObjectLabe()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glObjectPtrLabel(const void * ptr, GLsizei length, const GLchar * label)
+
+ Convenience function that calls glObjectPtrLabel(\a ptr, \a length, \a label).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glObjectPtrLabel.xml}{glObjectPtrLabe()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glPatchParameteri(GLenum pname, GLint value)
+
+ Convenience function that calls glPatchParameteri(\a pname, \a value).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glPatchParameteri.xml}{glPatchParameteri()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glPopDebugGroup(void)
+
+ Convenience function that calls glPopDebugGroup().
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glPopDebugGroup.xml}{glPopDebugGroup()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glPrimitiveBoundingBox(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW)
+
+ Convenience function that calls glPrimitiveBoundingBox(\a minX, \a minY, \a minZ, \a minW, \a maxX, \a maxY, \a maxZ, \a maxW).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glPrimitiveBoundingBox.xml}{glPrimitiveBoundingBo()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glPushDebugGroup(GLenum source, GLuint id, GLsizei length, const GLchar * message)
+
+ Convenience function that calls glPushDebugGroup(\a source, \a id, \a length, \a message).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glPushDebugGroup.xml}{glPushDebugGroup()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glReadnPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data)
+
+ Convenience function that calls glReadnPixels(\a x, \a y, \a width, \a height, \a format, \a type, \a bufSize, \a data).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glReadnPixels.xml}{glReadnPixels()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glSamplerParameterIiv(GLuint sampler, GLenum pname, const GLint * param)
+
+ Convenience function that calls glSamplerParameterIiv(\a sampler, \a pname, \a param).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glSamplerParameterIiv.xml}{glSamplerParameterIiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glSamplerParameterIuiv(GLuint sampler, GLenum pname, const GLuint * param)
+
+ Convenience function that calls glSamplerParameterIuiv(\a sampler, \a pname, \a param).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glSamplerParameterIuiv.xml}{glSamplerParameterIuiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glTexBuffer(GLenum target, GLenum internalformat, GLuint buffer)
+
+ Convenience function that calls glTexBuffer(\a target, \a internalformat, \a buffer).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glTexBuffer.xml}{glTexBuffer()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glTexBufferRange(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size)
+
+ Convenience function that calls glTexBufferRange(\a target, \a internalformat, \a buffer, \a offset, \a size).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glTexBufferRange.xml}{glTexBufferRange()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glTexParameterIiv(GLenum target, GLenum pname, const GLint * params)
+
+ Convenience function that calls glTexParameterIiv(\a target, \a pname, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glTexParameterIiv.xml}{glTexParameterIiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glTexParameterIuiv(GLenum target, GLenum pname, const GLuint * params)
+
+ Convenience function that calls glTexParameterIuiv(\a target, \a pname, \a params).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glTexParameterIuiv.xml}{glTexParameterIuiv()}.
+*/
+
+/*!
+ \fn void QOpenGLExtraFunctions::glTexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations)
+
+ Convenience function that calls glTexStorage3DMultisample(\a target, \a samples, \a internalformat, \a width, \a height, \a depth, \a fixedsamplelocations).
+
+ This function is only available in OpenGL ES 3.x, or OpenGL 3.x or 4.x contexts. When running
+ with plain OpenGL, the function is only usable when the given profile and version contains the
+ function either in core or as an extension.
+
+ For more information, see the OpenGL ES 3.2 documentation for
+ \l{http://www.khronos.org/opengles/sdk/docs/man32/glTexStorage3DMultisample.xml}{glTexStorage3DMultisample()}.
+*/
+
+/*!
\fn bool QOpenGLExtraFunctions::isInitialized(const QOpenGLExtraFunctionsPrivate *d)
\internal
*/
diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp
index 58dcbed50a..3aa4c0d2e6 100644
--- a/src/gui/opengl/qopenglgradientcache.cpp
+++ b/src/gui/opengl/qopenglgradientcache.cpp
@@ -42,6 +42,7 @@
#include <private/qopenglcontext_p.h>
#include <private/qrgba64_p.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qrandom.h>
#include "qopenglfunctions.h"
#include "qopenglextensions_p.h"
@@ -137,7 +138,7 @@ GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient
{
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (cache.size() == maxCacheSize()) {
- int elem_to_remove = qrand() % maxCacheSize();
+ int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize());
quint64 key = cache.keys()[elem_to_remove];
// need to call glDeleteTextures on each removed cache entry:
diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp
index 766d4a327a..3563f1b5d3 100644
--- a/src/gui/opengl/qopengltexture.cpp
+++ b/src/gui/opengl/qopengltexture.cpp
@@ -43,6 +43,7 @@
#include "qopenglfunctions.h"
#include <QtGui/qcolor.h>
#include <QtGui/qopenglcontext.h>
+#include <QtCore/qdebug.h>
#include <private/qobject_p.h>
#include <private/qopenglcontext_p.h>
@@ -190,11 +191,20 @@ void QOpenGLTexturePrivate::destroy()
return;
}
QOpenGLContext *currentContext = QOpenGLContext::currentContext();
- if (!currentContext || !QOpenGLContext::areSharing(currentContext, context)) {
- qWarning("Texture is not valid in the current context.\n"
+ if (!currentContext) {
+ qWarning("QOpenGLTexturePrivate::destroy() called without a current context.\n"
"Texture has not been destroyed");
return;
}
+ if (!QOpenGLContext::areSharing(currentContext, context)) {
+
+ qWarning("QOpenGLTexturePrivate::destroy() called but texture context %p"
+ " is not shared with current context %p.\n"
+ "Texture has not been destroyed",
+ static_cast<const void *>(context),
+ static_cast<const void *>(currentContext));
+ return;
+ }
functions->glDeleteTextures(1, &textureId);
@@ -4661,4 +4671,40 @@ float QOpenGLTexture::levelofDetailBias() const
return d->levelOfDetailBias;
}
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QOpenGLTexture *t)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QOpenGLTexture(";
+ if (t) {
+ const QOpenGLTexturePrivate *d = t->d_ptr.data();
+ debug << d->target << ", bindingTarget=" << d->bindingTarget
+ << ", size=[" << d->dimensions[0]
+ << ", " << d->dimensions[1];
+ if (d->target == QOpenGLTexture::Target3D)
+ debug << ", " << d->dimensions[2];
+ debug << "], format=" << d->format << ", formatClass=" << d->formatClass;
+ if (t->isCreated())
+ debug << ", textureId=" << d->textureId;
+ if (t->isBound())
+ debug << ", [bound]";
+ if (t->isTextureView())
+ debug << ", [view]";
+ if (d->fixedSamplePositions)
+ debug << ", [fixedSamplePositions]";
+ debug << ", mipLevels=" << d->requestedMipLevels << ", layers=" << d->layers
+ << ", faces=" << d->faces << ", samples=" << d->samples
+ << ", depthStencilMode=" << d->depthStencilMode << ", comparisonFunction="
+ << d->comparisonFunction << ", comparisonMode=" << d->comparisonMode
+ << ", features=" << d->features << ", minificationFilter=" << d->minFilter
+ << ", magnificationFilter=" << d->magFilter << ", wrapMode=" << d->wrapModes[0];
+ } else {
+ debug << '0';
+ }
+ debug << ')';
+ return debug;
+}
+#endif // QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h
index 6e6f7ef1f2..12d9b91603 100644
--- a/src/gui/opengl/qopengltexture.h
+++ b/src/gui/opengl/qopengltexture.h
@@ -50,6 +50,7 @@
QT_BEGIN_NAMESPACE
+class QDebug;
class QOpenGLTexturePrivate;
class QOpenGLPixelTransferOptions;
@@ -613,6 +614,10 @@ public:
void setLevelofDetailBias(float bias);
float levelofDetailBias() const;
+#ifndef QT_NO_DEBUG_STREAM
+ friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QOpenGLTexture *t);
+#endif
+
private:
Q_DISABLE_COPY(QOpenGLTexture)
Q_DECLARE_PRIVATE(QOpenGLTexture)
@@ -621,6 +626,10 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTexture::Features)
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLTexture *t);
+#endif
+
QT_END_NAMESPACE
#endif // QT_NO_OPENGL
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 63e345545c..9ff0b5f5e5 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -99,6 +99,9 @@ SOURCES += \
painting/qplatformbackingstore.cpp \
painting/qpathsimplifier.cpp
+RESOURCES += \
+ painting/qpdf.qrc
+
darwin {
HEADERS += painting/qcoregraphics_p.h
SOURCES += painting/qcoregraphics.mm
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index afd39a6b71..8d71d1c3a9 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -90,50 +90,6 @@ public:
*/
/*!
- Flushes the given \a region from the specified window \a win onto the
- screen.
-
- Note that the \a offset parameter is currently unused.
-*/
-void QBackingStore::flush(const QRegion &region, QWindow *win, const QPoint &offset)
-{
- if (!win)
- win = window();
- if (!win->handle()) {
- qWarning() << "QBackingStore::flush() called for "
- << win << " which does not have a handle.";
- return;
- }
-
-#ifdef QBACKINGSTORE_DEBUG
- if (win && win->isTopLevel() && !qt_window_private(win)->receivedExpose) {
- qWarning().nospace() << "QBackingStore::flush() called with non-exposed window "
- << win << ", behavior is undefined";
- }
-#endif
-
- Q_ASSERT(win == this->window() || this->window()->isAncestorOf(win, QWindow::ExcludeTransients));
-
- d_ptr->platformBackingStore->flush(win, QHighDpi::toNativeLocalRegion(region, win),
- QHighDpi::toNativeLocalPosition(offset, win));
-}
-
-/*!
- \fn QPaintDevice* QBackingStore::paintDevice()
-
- Implement this function to return the appropriate paint device.
-*/
-QPaintDevice *QBackingStore::paintDevice()
-{
- QPaintDevice *device = d_ptr->platformBackingStore->paintDevice();
-
- if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image)
- return d_ptr->highDpiBackingstore.data();
-
- return device;
-}
-
-/*!
Constructs an empty surface for the given top-level \a window.
*/
QBackingStore::QBackingStore(QWindow *window)
@@ -161,8 +117,10 @@ QWindow* QBackingStore::window() const
}
/*!
- This function is called before painting onto the surface begins,
- with the \a region in which the painting will occur.
+ Begins painting on the backing store surface in the given \a region.
+
+ You should call this function before using the paintDevice() to
+ paint.
\sa endPaint(), paintDevice()
*/
@@ -203,7 +161,26 @@ void QBackingStore::beginPaint(const QRegion &region)
}
/*!
- This function is called after painting onto the surface has ended.
+ Returns the paint device for this surface.
+
+ \warning The device is only valid between calls to beginPaint() and
+ endPaint(). You should not cache the returned value.
+*/
+QPaintDevice *QBackingStore::paintDevice()
+{
+ QPaintDevice *device = d_ptr->platformBackingStore->paintDevice();
+
+ if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image)
+ return d_ptr->highDpiBackingstore.data();
+
+ return device;
+}
+
+/*!
+ Ends painting.
+
+ You should call this function after painting with the paintDevice()
+ has ended.
\sa beginPaint(), paintDevice()
*/
@@ -216,9 +193,50 @@ void QBackingStore::endPaint()
}
/*!
- Sets the size of the windowsurface to be \a size.
+ Flushes the given \a region from the specified \a window onto the
+ screen.
+
+ The \a window must either be the top level window represented by
+ this backingstore, or a non-transient child of that window. Passing
+ \c nullptr falls back to using the backingstore's top level window.
+
+ If the \a window is a child window, the \a region should be in child window
+ coordinates, and the \a offset should be the child window's offset in relation
+ to the backingstore's top level window.
+
+ You should call this function after ending painting with endPaint().
+
+ \sa QWindow::transientParent()
+*/
+void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &offset)
+{
+ QWindow *topLevelWindow = this->window();
+
+ if (!window)
+ window = topLevelWindow;
+ if (!window->handle()) {
+ qWarning() << "QBackingStore::flush() called for "
+ << window << " which does not have a handle.";
+ return;
+ }
+
+#ifdef QBACKINGSTORE_DEBUG
+ if (window && window->isTopLevel() && !qt_window_private(window)->receivedExpose) {
+ qWarning().nospace() << "QBackingStore::flush() called with non-exposed window "
+ << window << ", behavior is undefined";
+ }
+#endif
+
+ Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients));
+
+ d_ptr->platformBackingStore->flush(window, QHighDpi::toNativeLocalRegion(region, window),
+ QHighDpi::toNativeLocalPosition(offset, window));
+}
+
+/*!
+ Sets the size of the window surface to \a size.
- \sa size()
+ \sa size()
*/
void QBackingStore::resize(const QSize &size)
{
@@ -227,7 +245,7 @@ void QBackingStore::resize(const QSize &size)
}
/*!
- Returns the current size of the windowsurface.
+ Returns the current size of the window surface.
*/
QSize QBackingStore::size() const
{
@@ -255,7 +273,7 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
}
/*!
- Set \a region as the static contents of this window.
+ Set \a region as the static contents of this window.
*/
void QBackingStore::setStaticContents(const QRegion &region)
{
@@ -263,8 +281,8 @@ void QBackingStore::setStaticContents(const QRegion &region)
}
/*!
- Returns a pointer to the QRegion that has the static contents
- of this window.
+ Returns a QRegion representing the area of the window that
+ has static contents.
*/
QRegion QBackingStore::staticContents() const
{
@@ -272,8 +290,7 @@ QRegion QBackingStore::staticContents() const
}
/*!
- Returns a boolean indicating if this window
- has static contents or not.
+ Returns a boolean indicating if this window has static contents or not.
*/
bool QBackingStore::hasStaticContents() const
{
@@ -328,7 +345,7 @@ void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPo
}
/*!
- Returns a pointer to the QPlatformBackingStore implementation
+ Returns a pointer to the QPlatformBackingStore implementation
*/
QPlatformBackingStore *QBackingStore::handle() const
{
diff --git a/src/gui/painting/qbackingstore.h b/src/gui/painting/qbackingstore.h
index 2ba6e1c906..ed37e11a5b 100644
--- a/src/gui/painting/qbackingstore.h
+++ b/src/gui/painting/qbackingstore.h
@@ -66,9 +66,7 @@ public:
QPaintDevice *paintDevice();
- // 'window' can be a child window, in which case 'region' is in child window coordinates and
- // offset is the (child) window's offset in relation to the window surface.
- void flush(const QRegion &region, QWindow *window = Q_NULLPTR, const QPoint &offset = QPoint());
+ void flush(const QRegion &region, QWindow *window = nullptr, const QPoint &offset = QPoint());
void resize(const QSize &size);
QSize size() const;
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index cc3ee76f0d..5c13308d94 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -100,7 +100,7 @@ const uchar *qt_patternForBrush(int brushStyle, bool invert)
return pat_tbl[brushStyle - Qt::Dense1Pattern][invert];
}
-QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
+Q_GUI_EXPORT QPixmap qt_pixmapForBrush(int brushStyle, bool invert)
{
QPixmap pm;
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index 6e0e348a67..c55bcb12c9 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -79,7 +79,7 @@ static inline int hex2int(char s)
return h < 0 ? h : (h << 4) | h;
}
-static bool get_hex_rgb(const char *name, int len, QRgb *rgb)
+static bool get_hex_rgb(const char *name, size_t len, QRgb *rgb)
{
if (name[0] != '#')
return false;
@@ -124,12 +124,12 @@ bool qt_get_hex_rgb(const char *name, QRgb *rgb)
return get_hex_rgb(name, qstrlen(name), rgb);
}
-static bool get_hex_rgb(const QChar *str, int len, QRgb *rgb)
+static bool get_hex_rgb(const QChar *str, size_t len, QRgb *rgb)
{
if (len > 13)
return false;
char tmp[16];
- for (int i = 0; i < len; ++i)
+ for (size_t i = 0; i < len; ++i)
tmp[i] = str[i].toLatin1();
tmp[len] = 0;
return get_hex_rgb(tmp, len, rgb);
@@ -858,6 +858,7 @@ QString QColor::name(NameFormat format) const
return QString();
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Sets the RGB value of this QColor to \a name, which may be in one
of these formats:
@@ -883,6 +884,17 @@ QString QColor::name(NameFormat format) const
void QColor::setNamedColor(const QString &name)
{
+ setColorFromString(qToStringViewIgnoringNull(name));
+}
+#endif
+
+/*!
+ \overload
+ \since 5.10
+*/
+
+void QColor::setNamedColor(QStringView name)
+{
setColorFromString(name);
}
@@ -896,6 +908,7 @@ void QColor::setNamedColor(QLatin1String name)
setColorFromString(name);
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
\since 4.7
@@ -909,7 +922,17 @@ void QColor::setNamedColor(QLatin1String name)
*/
bool QColor::isValidColor(const QString &name)
{
- return !name.isEmpty() && QColor().setColorFromString(name);
+ return isValidColor(qToStringViewIgnoringNull(name));
+}
+#endif
+
+/*!
+ \overload
+ \since 5.10
+*/
+bool QColor::isValidColor(QStringView name) Q_DECL_NOTHROW
+{
+ return name.size() && QColor().setColorFromString(name);
}
/*!
@@ -922,7 +945,7 @@ bool QColor::isValidColor(QLatin1String name) Q_DECL_NOTHROW
}
template <typename String>
-bool QColor::setColorFromString(const String &name)
+bool QColor::setColorFromString(String name)
{
if (!name.size()) {
invalidate();
diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h
index 83a93e25ea..0c5ebcbda9 100644
--- a/src/gui/painting/qcolor.h
+++ b/src/gui/painting/qcolor.h
@@ -72,7 +72,10 @@ public:
inline QColor(int r, int g, int b, int a = 255);
QColor(QRgb rgb) Q_DECL_NOTHROW;
QColor(QRgba64 rgba64) Q_DECL_NOTHROW;
+#if QT_STRINGVIEW_LEVEL < 2
inline QColor(const QString& name);
+#endif
+ explicit inline QColor(QStringView name);
inline QColor(const char *aname) : QColor(QLatin1String(aname)) {}
inline QColor(QLatin1String name);
QColor(Spec spec) Q_DECL_NOTHROW;
@@ -95,7 +98,10 @@ public:
QString name() const;
QString name(NameFormat format) const;
+#if QT_STRINGVIEW_LEVEL < 2
void setNamedColor(const QString& name);
+#endif
+ void setNamedColor(QStringView name);
void setNamedColor(QLatin1String name);
static QStringList colorNames();
@@ -221,14 +227,17 @@ public:
operator QVariant() const;
+#if QT_STRINGVIEW_LEVEL < 2
static bool isValidColor(const QString &name);
+#endif
+ static bool isValidColor(QStringView) Q_DECL_NOTHROW;
static bool isValidColor(QLatin1String) Q_DECL_NOTHROW;
private:
void invalidate() Q_DECL_NOTHROW;
template <typename String>
- bool setColorFromString(const String &name);
+ bool setColorFromString(String name);
Spec cspec;
union {
@@ -280,8 +289,13 @@ inline QColor::QColor(int r, int g, int b, int a)
inline QColor::QColor(QLatin1String aname)
{ setNamedColor(aname); }
+inline QColor::QColor(QStringView aname)
+{ setNamedColor(aname); }
+
+#if QT_STRINGVIEW_LEVEL < 2
inline QColor::QColor(const QString& aname)
{ setNamedColor(aname); }
+#endif
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
inline QColor::QColor(const QColor &acolor) Q_DECL_NOTHROW
diff --git a/src/gui/painting/qcompositionfunctions.cpp b/src/gui/painting/qcompositionfunctions.cpp
index 6d2cb9aadb..ee05f810f1 100644
--- a/src/gui/painting/qcompositionfunctions.cpp
+++ b/src/gui/painting/qcompositionfunctions.cpp
@@ -855,6 +855,10 @@ struct QFullCoverage {
{
*dest = src;
}
+ inline void store(QRgba64 *dest, const QRgba64 src) const
+ {
+ *dest = src;
+ }
};
struct QPartialCoverage {
@@ -868,6 +872,10 @@ struct QPartialCoverage {
{
*dest = INTERPOLATE_PIXEL_255(src, ca, *dest, ica);
}
+ inline void store(QRgba64 *dest, const QRgba64 src) const
+ {
+ *dest = interpolate255(src, ca, *dest, ica);
+ }
private:
const uint ca;
@@ -879,6 +887,11 @@ static inline int mix_alpha(int da, int sa)
return 255 - ((255 - sa) * (255 - da) >> 8);
}
+static inline uint mix_alpha_rgb64(uint da, uint sa)
+{
+ return 65535 - ((65535 - sa) * (65535 - da) >> 16);
+}
+
/*
Dca' = Sca.Da + Dca.Sa + Sca.(1 - Da) + Dca.(1 - Sa)
= Sca + Dca
@@ -897,17 +910,6 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int
}
}
-template <typename T>
-Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl_rgb64(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
-{
- QRgba64 s = color;
- for (int i = 0; i < length; ++i) {
- QRgba64 d = dest[i];
- d = comp_func_Plus_one_pixel(d, s);
- coverage.store(&dest[i], d);
- }
-}
-
void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -986,6 +988,11 @@ static inline int multiply_op(int dst, int src, int da, int sa)
return qt_div_255(src * dst + src * (255 - da) + dst * (255 - sa));
}
+static inline uint multiply_op_rgb64(uint dst, uint src, uint da, uint sa)
+{
+ return qt_div_65535(src * dst + src * (65535 - da) + dst * (65535 - sa));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1011,6 +1018,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest,
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) multiply_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1019,6 +1049,14 @@ void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint color, ui
comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_Multiply_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Multiply_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Multiply_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1042,6 +1080,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *Q_DECL_REST
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) multiply_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1050,6 +1109,14 @@ void QT_FASTCALL comp_func_Multiply(uint *Q_DECL_RESTRICT dest, const uint *Q_DE
comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_Multiply_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Multiply_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Multiply_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
Dca' = (Sca.Da + Dca.Sa - Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
= Sca + Dca - Sca.Dca
@@ -1079,6 +1146,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, i
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) 65535 - qt_div_65535((65535-a) * (65535-b))
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1087,6 +1177,14 @@ void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint color, uint
comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_Screen_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Screen_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Screen_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1110,6 +1208,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *Q_DECL_RESTRI
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) 65535 - (((65535-a) * (65535-b)) >> 16)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1118,6 +1237,14 @@ void QT_FASTCALL comp_func_Screen(uint *dest, const uint *src, int length, uint
comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_Screen_rgb64(QRgba64 *dest, const QRgba64 *src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Screen_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Screen_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
if 2.Dca < Da
Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1133,6 +1260,15 @@ static inline int overlay_op(int dst, int src, int da, int sa)
return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
}
+static inline uint overlay_op_rgb64(uint dst, uint src, uint da, uint sa)
+{
+ const uint temp = src * (65535 - da) + dst * (65535 - sa);
+ if (2 * dst < da)
+ return qt_div_65535(2 * src * dst + temp);
+ else
+ return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp);
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1158,6 +1294,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest,
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) overlay_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1166,6 +1325,14 @@ void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint color, uin
comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_Overlay_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Overlay_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Overlay_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1189,6 +1356,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *Q_DECL_RESTR
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) overlay_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1197,6 +1385,14 @@ void QT_FASTCALL comp_func_Overlay(uint *Q_DECL_RESTRICT dest, const uint *Q_DEC
comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_Overlay_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Overlay_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Overlay_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
Da' = Sa + Da - Sa.Da
@@ -1206,6 +1402,11 @@ static inline int darken_op(int dst, int src, int da, int sa)
return qt_div_255(qMin(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
}
+static inline uint darken_op_rgb64(uint dst, uint src, uint da, uint sa)
+{
+ return qt_div_65535(qMin(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1231,6 +1432,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, i
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) darken_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1239,6 +1463,14 @@ void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint color, uint
comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_Darken_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Darken_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Darken_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1262,6 +1494,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *Q_DECL_RESTRI
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) darken_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1270,6 +1523,14 @@ void QT_FASTCALL comp_func_Darken(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL
comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_Darken_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Darken_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Darken_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa)
Da' = Sa + Da - Sa.Da
@@ -1279,6 +1540,11 @@ static inline int lighten_op(int dst, int src, int da, int sa)
return qt_div_255(qMax(src * da, dst * sa) + src * (255 - da) + dst * (255 - sa));
}
+static inline uint lighten_op_rgb64(uint dst, uint src, uint da, uint sa)
+{
+ return qt_div_65535(qMax(src * da, dst * sa) + src * (65535 - da) + dst * (65535 - sa));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1304,6 +1570,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest,
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) lighten_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1312,6 +1601,14 @@ void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint color, uin
comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_Lighten_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Lighten_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Lighten_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1335,6 +1632,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *Q_DECL_RESTR
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) lighten_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1343,6 +1661,14 @@ void QT_FASTCALL comp_func_Lighten(uint *Q_DECL_RESTRICT dest, const uint *Q_DEC
comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_Lighten_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Lighten_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Lighten_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
if Sca.Da + Dca.Sa >= Sa.Da
Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1362,6 +1688,19 @@ static inline int color_dodge_op(int dst, int src, int da, int sa)
return qt_div_255(255 * dst_sa / (255 - 255 * src / sa) + temp);
}
+static inline uint color_dodge_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
+{
+ const qint64 sa_da = sa * da;
+ const qint64 dst_sa = dst * sa;
+ const qint64 src_da = src * da;
+
+ const qint64 temp = src * (65535 - da) + dst * (65535 - sa);
+ if (src_da + dst_sa >= sa_da)
+ return qt_div_65535(sa_da + temp);
+ else
+ return qt_div_65535(65535 * dst_sa / (65535 - 65535 * src / sa) + temp);
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1387,6 +1726,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *des
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a,b) color_dodge_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1395,6 +1757,14 @@ void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint color,
comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_ColorDodge_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_ColorDodge_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_ColorDodge_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1418,6 +1788,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *Q_DECL_RE
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) color_dodge_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1426,6 +1817,14 @@ void QT_FASTCALL comp_func_ColorDodge(uint *Q_DECL_RESTRICT dest, const uint *Q_
comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_ColorDodge_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_ColorDodge_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_ColorDodge_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
if Sca.Da + Dca.Sa <= Sa.Da
Dca' = Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1445,6 +1844,19 @@ static inline int color_burn_op(int dst, int src, int da, int sa)
return qt_div_255(sa * (src_da + dst_sa - sa_da) / src + temp);
}
+static inline uint color_burn_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
+{
+ const qint64 src_da = src * da;
+ const qint64 dst_sa = dst * sa;
+ const qint64 sa_da = sa * da;
+
+ const qint64 temp = src * (65535 - da) + dst * (65535 - sa);
+
+ if (src == 0 || src_da + dst_sa <= sa_da)
+ return qt_div_65535(temp);
+ return qt_div_65535(sa * (src_da + dst_sa - sa_da) / src + temp);
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1470,6 +1882,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) color_burn_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1478,6 +1913,14 @@ void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint color, u
comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_ColorBurn_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_ColorBurn_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_ColorBurn_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1501,6 +1944,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *Q_DECL_RES
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) color_burn_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1509,6 +1973,14 @@ void QT_FASTCALL comp_func_ColorBurn(uint *Q_DECL_RESTRICT dest, const uint *Q_D
comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_ColorBurn_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_ColorBurn_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_ColorBurn_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
if 2.Sca < Sa
Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1525,6 +1997,16 @@ static inline uint hardlight_op(int dst, int src, int da, int sa)
return qt_div_255(sa * da - 2 * (da - dst) * (sa - src) + temp);
}
+static inline uint hardlight_op_rgb64(uint dst, uint src, uint da, uint sa)
+{
+ const uint temp = src * (65535 - da) + dst * (65535 - sa);
+
+ if (2 * src < sa)
+ return qt_div_65535(2 * src * dst + temp);
+ else
+ return qt_div_65535(sa * da - 2 * (da - dst) * (sa - src) + temp);
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1550,6 +2032,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) hardlight_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1558,6 +2063,14 @@ void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint color, u
comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_HardLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_HardLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_HardLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1581,6 +2094,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *Q_DECL_RES
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) hardlight_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1589,6 +2123,14 @@ void QT_FASTCALL comp_func_HardLight(uint *Q_DECL_RESTRICT dest, const uint *Q_D
comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_HardLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_HardLight_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_HardLight_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
if 2.Sca <= Sa
Dca' = Dca.(Sa + (2.Sca - Sa).(1 - Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa)
@@ -1612,6 +2154,22 @@ static inline int soft_light_op(int dst, int src, int da, int sa)
}
}
+static inline uint soft_light_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
+{
+ const qint64 src2 = src << 1;
+ const qint64 dst_np = da != 0 ? (65535 * dst) / da : 0;
+ const qint64 temp = (src * (65535 - da) + dst * (65535 - sa)) * 65535;
+ const qint64 factor = qint64(65535) * 65535;
+
+ if (src2 < sa)
+ return (dst * (sa * 65535 + (src2 - sa) * (65535 - dst_np)) + temp) / factor;
+ else if (4 * dst <= da)
+ return (dst * sa * 65535 + da * (src2 - sa) * ((((16 * dst_np - 12 * 65535) * dst_np + 3 * factor) * dst_np) / factor) + temp) / factor;
+ else {
+ return (dst * sa * 65535 + da * (src2 - sa) * (int(qSqrt(qreal(dst_np * 65535))) - dst_np) + temp) / factor;
+ }
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1637,6 +2195,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) soft_light_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1645,6 +2226,14 @@ void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint color, u
comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_SoftLight_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_SoftLight_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_SoftLight_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1668,6 +2257,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *Q_DECL_RES
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) soft_light_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1676,6 +2286,14 @@ void QT_FASTCALL comp_func_SoftLight(uint *Q_DECL_RESTRICT dest, const uint *Q_D
comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_SoftLight_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_SoftLight_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_SoftLight_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
= Sca + Dca - 2.min(Sca.Da, Dca.Sa)
@@ -1685,6 +2303,11 @@ static inline int difference_op(int dst, int src, int da, int sa)
return src + dst - qt_div_255(2 * qMin(src * da, dst * sa));
}
+static inline uint difference_op_rgb64(qint64 dst, qint64 src, qint64 da, qint64 sa)
+{
+ return src + dst - qt_div_65535(2 * qMin(src * da, dst * sa));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *dest, int length, uint color, const T &coverage)
{
@@ -1710,6 +2333,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *des
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) difference_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1718,6 +2364,14 @@ void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint color,
comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_Difference_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Difference_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Difference_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1741,6 +2395,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *Q_DECL_RE
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) difference_op_rgb64(a, b, da, sa)
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1749,6 +2424,14 @@ void QT_FASTCALL comp_func_Difference(uint *Q_DECL_RESTRICT dest, const uint *Q_
comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_Difference_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Difference_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Difference_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
/*
Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)
*/
@@ -1777,6 +2460,30 @@ Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_imp
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_impl(QRgba64 *dest, int length, QRgba64 color, const T &coverage)
+{
+ uint sa = color.alpha();
+ uint sr = color.red();
+ uint sg = color.green();
+ uint sb = color.blue();
+
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ uint da = d.alpha();
+
+#define OP(a, b) (a + b - qt_div_65535(2*(qint64(a)*b)))
+ uint r = OP( d.red(), sr);
+ uint b = OP( d.blue(), sb);
+ uint g = OP(d.green(), sg);
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
+
void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, uint const_alpha)
{
if (const_alpha == 255)
@@ -1785,6 +2492,14 @@ void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint color, u
comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_solid_Exclusion_rgb64(QRgba64 *dest, int length, QRgba64 color, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_solid_Exclusion_impl(dest, length, color, QFullCoverage());
+ else
+ comp_func_solid_Exclusion_impl(dest, length, color, QPartialCoverage(const_alpha));
+}
+
template <typename T>
Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, const T &coverage)
{
@@ -1808,6 +2523,27 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *Q_DECL_RES
}
}
+template <typename T>
+Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, const T &coverage)
+{
+ for (int i = 0; i < length; ++i) {
+ QRgba64 d = dest[i];
+ QRgba64 s = src[i];
+
+ uint da = d.alpha();
+ uint sa = s.alpha();
+
+#define OP(a, b) (a + b - ((qint64(a)*b) >> 15))
+ uint r = OP( d.red(), s.red());
+ uint b = OP( d.blue(), s.blue());
+ uint g = OP(d.green(), s.green());
+ uint a = mix_alpha_rgb64(da, sa);
+#undef OP
+
+ coverage.store(&dest[i], qRgba64(r, g, b, a));
+ }
+}
+
void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_DECL_RESTRICT src, int length, uint const_alpha)
{
if (const_alpha == 255)
@@ -1816,6 +2552,14 @@ void QT_FASTCALL comp_func_Exclusion(uint *Q_DECL_RESTRICT dest, const uint *Q_D
comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
}
+void QT_FASTCALL comp_func_Exclusion_rgb64(QRgba64 *Q_DECL_RESTRICT dest, const QRgba64 *Q_DECL_RESTRICT src, int length, uint const_alpha)
+{
+ if (const_alpha == 255)
+ comp_func_Exclusion_impl(dest, src, length, QFullCoverage());
+ else
+ comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha));
+}
+
void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest,
int length,
uint color,
@@ -2177,8 +2921,17 @@ CompositionFunctionSolid64 qt_functionForModeSolid64_C[] = {
comp_func_solid_DestinationAtop_rgb64,
comp_func_solid_XOR_rgb64,
comp_func_solid_Plus_rgb64,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
+ comp_func_solid_Multiply_rgb64,
+ comp_func_solid_Screen_rgb64,
+ comp_func_solid_Overlay_rgb64,
+ comp_func_solid_Darken_rgb64,
+ comp_func_solid_Lighten_rgb64,
+ comp_func_solid_ColorDodge_rgb64,
+ comp_func_solid_ColorBurn_rgb64,
+ comp_func_solid_HardLight_rgb64,
+ comp_func_solid_SoftLight_rgb64,
+ comp_func_solid_Difference_rgb64,
+ comp_func_solid_Exclusion_rgb64,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
@@ -2238,8 +2991,17 @@ CompositionFunction64 qt_functionForMode64_C[] = {
comp_func_DestinationAtop_rgb64,
comp_func_XOR_rgb64,
comp_func_Plus_rgb64,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
+ comp_func_Multiply_rgb64,
+ comp_func_Screen_rgb64,
+ comp_func_Overlay_rgb64,
+ comp_func_Darken_rgb64,
+ comp_func_Lighten_rgb64,
+ comp_func_ColorDodge_rgb64,
+ comp_func_ColorBurn_rgb64,
+ comp_func_HardLight_rgb64,
+ comp_func_SoftLight_rgb64,
+ comp_func_Difference_rgb64,
+ comp_func_Exclusion_rgb64,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
diff --git a/src/gui/painting/qcoregraphics.mm b/src/gui/painting/qcoregraphics.mm
index c4fb8afc64..e1601d87dc 100644
--- a/src/gui/painting/qcoregraphics.mm
+++ b/src/gui/painting/qcoregraphics.mm
@@ -66,7 +66,7 @@ CGImageRef qt_mac_toCGImageMask(const QImage &image)
static const auto deleter = [](void *image, const void *, size_t) { delete static_cast<QImage *>(image); };
QCFType<CGDataProviderRef> dataProvider =
CGDataProviderCreateWithData(new QImage(image), image.bits(),
- image.byteCount(), deleter);
+ image.sizeInBytes(), deleter);
return CGImageMaskCreate(image.width(), image.height(), 8, image.depth(),
image.bytesPerLine(), dataProvider, NULL, false);
@@ -110,6 +110,7 @@ NSImage *qt_mac_create_nsimage(const QPixmap &pm)
QImage image = pm.toImage();
CGImageRef cgImage = qt_mac_toCGImage(image);
NSImage *nsImage = qt_mac_cgimage_to_nsimage(cgImage);
+ nsImage.size = (pm.size() / pm.devicePixelRatioF()).toCGSize();
CGImageRelease(cgImage);
return nsImage;
}
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
index bcb243db6a..436a62d486 100644
--- a/src/gui/painting/qcosmeticstroker.cpp
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -292,7 +292,7 @@ void QCosmeticStroker::setup()
color = multiplyAlpha256(state->penData.solid.color, opacity).toArgb32();
QRasterBuffer *buffer = state->penData.rasterBuffer;
pixels = (uint *)buffer->buffer();
- ppl = buffer->bytesPerLine()>>2;
+ ppl = buffer->stride<quint32>();
}
// line drawing produces different results with different clips, so
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 6c25710271..6bfdc940ac 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -55,10 +55,13 @@
#endif
#include <private/qguiapplication_p.h>
#include <private/qrgba64_p.h>
+#include <qloggingcategory.h>
#include <qmath.h>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQtGuiDrawHelper, "qt.gui.drawhelper")
+
#define MASK(src, a) src = BYTE_MUL(src, a)
/*
@@ -1042,7 +1045,7 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
{ 10, 20, 10, 10, 10, 0, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderBGR>, convertA2RGB30PMFromARGB32PM<PixelOrderBGR>, convertRGB30FromRGB32<PixelOrderBGR>, convertA2RGB30PMToARGB64PM<PixelOrderBGR> }, // Format_A2BGR30_Premultiplied
{ 10, 0, 10, 10, 10, 20, 0, 30, false, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertRGB30FromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_RGB30
{ 10, 0, 10, 10, 10, 20, 2, 30, true, QPixelLayout::BPP32, convertA2RGB30PMToARGB32PM<PixelOrderRGB>, convertA2RGB30PMFromARGB32PM<PixelOrderRGB>, convertRGB30FromRGB32<PixelOrderRGB>, convertA2RGB30PMToARGB64PM<PixelOrderRGB> }, // Format_A2RGB30_Premultiplied
- { 0, 0, 0, 0, 0, 0, 8, 0, false, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8
+ { 0, 0, 0, 0, 0, 0, 8, 0, true, QPixelLayout::BPP8, convertAlpha8ToRGB32, convertAlpha8FromARGB32PM, 0, convertAlpha8ToRGB64 }, // Format_Alpha8
{ 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertGrayscale8ToRGB32, convertGrayscale8FromARGB32PM, convertGrayscale8FromRGB32, convertGrayscale8ToRGB64 } // Format_Grayscale8
};
@@ -1942,10 +1945,14 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
const uint *s1 = (const uint *)image.scanLine(y1);
const uint *s2 = (const uint *)image.scanLine(y2);
- int disty = (fy & 0x0000ffff) >> 8;
- int idisty = 256 - disty;
- int x = fx >> 16;
- int length = end - b;
+ const int disty = (fy & 0x0000ffff) >> 8;
+ const int idisty = 256 - disty;
+ const int length = end - b;
+
+ // The intermediate buffer is generated in the positive direction
+ const int adjust = (fdx < 0) ? fdx * length : 0;
+ const int offset = (fx + adjust) >> 16;
+ int x = offset;
// The idea is first to do the interpolation between the row s1 and the row s2
// into an intermediate buffer, then we interpolate between two pixel of this buffer.
@@ -1955,7 +1962,7 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
// +1 for the last pixel to interpolate with, and +1 for rounding errors.
quint32 intermediate_buffer[2][buffer_size + 2];
// count is the size used in the intermediate_buffer.
- int count = (qint64(length) * fdx + fixed_scale - 1) / fixed_scale + 2;
+ int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2;
Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
int f = 0;
int lim = count;
@@ -2056,9 +2063,10 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper(u
intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
x++;
}
+
// Now interpolate the values from the intermediate_buffer to get the final result.
- fx &= fixed_scale - 1;
- Q_ASSERT((fx >> 16) == 0);
+ fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates
+
while (b < end) {
int x1 = (fx >> 16);
int x2 = x1 + 1;
@@ -2375,7 +2383,7 @@ static void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper(uint
__m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy);
const uchar *textureData = image.imageData;
- const int bytesPerLine = image.bytesPerLine;
+ const qsizetype bytesPerLine = image.bytesPerLine;
const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0));
while (b < boundedEnd - 3) {
@@ -2588,14 +2596,14 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c
fy -= half_point;
if (fdy == 0) { // simple scale, no rotation or shear
- if (fdx <= fixed_scale && fdx > 0) {
- // simple scale up on X without mirroring
+ if (qAbs(fdx) <= fixed_scale) {
+ // simple scale up on X
bilinearFastTransformHelperARGB32PM[tiled][SimpleUpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
- } else if ((fdx < 0 && fdx > -(fixed_scale / 8)) || qAbs(data->m22) < qreal(1./8.)) {
- // scale up more than 8x (on either Y or on X mirrored)
+ } else if (qAbs(data->m22) < qreal(1./8.)) {
+ // scale up more than 8x (on Y)
bilinearFastTransformHelperARGB32PM[tiled][UpscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
} else {
- // scale down on X (or up on X mirrored less than 8x)
+ // scale down on X
bilinearFastTransformHelperARGB32PM[tiled][DownscaleTransform](b, end, data->texture, fx, fy, fdx, fdy);
}
} else { // rotation or shear
@@ -2658,6 +2666,245 @@ static const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, c
return buffer;
}
+template<TextureBlendType blendType, QPixelLayout::BPP bpp>
+static void QT_FASTCALL fetchTransformedBilinear_simple_upscale_helper(uint *b, uint *end, const QTextureData &image,
+ int &fx, int &fy, int fdx, int /*fdy*/)
+{
+ const QPixelLayout *layout = &qPixelLayouts[image.format];
+ const QVector<QRgb> *clut = image.colorTable;
+ Q_ASSERT(bpp == QPixelLayout::BPPNone || bpp == layout->bpp);
+ // When templated 'fetch' should be inlined at compile time:
+ const FetchPixelsFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixels[layout->bpp] : fetchPixels<bpp>;
+ const ConvertFunc convertToARGB32PM = layout->convertToARGB32PM;
+
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ const uchar *s1 = image.scanLine(y1);
+ const uchar *s2 = image.scanLine(y2);
+
+ const int disty = (fy & 0x0000ffff) >> 8;
+ const int idisty = 256 - disty;
+ const int length = end - b;
+
+ // The intermediate buffer is generated in the positive direction
+ const int adjust = (fdx < 0) ? fdx * length : 0;
+ const int offset = (fx + adjust) >> 16;
+ int x = offset;
+
+ // The idea is first to do the interpolation between the row s1 and the row s2
+ // into an intermediate buffer, then we interpolate between two pixel of this buffer.
+ // +1 for the last pixel to interpolate with, and +1 for rounding errors.
+ uint buf1[buffer_size + 2];
+ uint buf2[buffer_size + 2];
+ const uint *ptr1;
+ const uint *ptr2;
+
+ int count = (qint64(length) * qAbs(fdx) + fixed_scale - 1) / fixed_scale + 2;
+ Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
+
+ if (blendType == BlendTransformedBilinearTiled) {
+ x %= image.width;
+ if (x < 0)
+ x += image.width;
+ int len1 = qMin(count, image.width - x);
+ int len2 = qMin(x, count - len1);
+
+ ptr1 = fetch(buf1, s1, x, len1);
+ ptr1 = convertToARGB32PM(buf1, ptr1, len1, clut, 0);
+ ptr2 = fetch(buf2, s2, x, len1);
+ ptr2 = convertToARGB32PM(buf2, ptr2, len1, clut, 0);
+ for (int i = 0; i < len1; ++i) {
+ uint t = ptr1[i];
+ uint b = ptr2[i];
+ buf1[i] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ buf2[i] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ }
+
+ if (len2) {
+ ptr1 = fetch(buf1 + len1, s1, 0, len2);
+ ptr1 = convertToARGB32PM(buf1 + len1, ptr1, len2, clut, 0);
+ ptr2 = fetch(buf2 + len1, s2, 0, len2);
+ ptr2 = convertToARGB32PM(buf2 + len1, ptr2, len2, clut, 0);
+ for (int i = 0; i < len2; ++i) {
+ uint t = ptr1[i];
+ uint b = ptr2[i];
+ buf1[i + len1] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ }
+ }
+ for (int i = image.width; i < count; ++i) {
+ buf1[i] = buf1[i - image.width];
+ buf2[i] = buf2[i - image.width];
+ }
+ } else {
+ int start = qMax(x, image.x1);
+ int end = qMin(x + count, image.x2);
+ int len = qMax(1, end - start);
+ int leading = start - x;
+
+ ptr1 = fetch(buf1 + leading, s1, start, len);
+ ptr1 = convertToARGB32PM(buf1 + leading, ptr1, len, clut, 0);
+ ptr2 = fetch(buf2 + leading, s2, start, len);
+ ptr2 = convertToARGB32PM(buf2 + leading, ptr2, len, clut, 0);
+
+ for (int i = 0; i < len; ++i) {
+ uint t = ptr1[i];
+ uint b = ptr2[i];
+ buf1[i + leading] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ buf2[i + leading] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ }
+
+ for (int i = 0; i < leading; ++i) {
+ buf1[i] = buf1[leading];
+ buf2[i] = buf2[leading];
+ }
+ for (int i = leading + len; i < count; ++i) {
+ buf1[i] = buf1[i - 1];
+ buf2[i] = buf2[i - 1];
+ }
+ }
+
+ // Now interpolate the values from the intermediate_buffer to get the final result.
+ fx -= offset * fixed_scale; // Switch to intermediate buffer coordinates
+
+ while (b < end) {
+ int x1 = (fx >> 16);
+ int x2 = x1 + 1;
+ Q_ASSERT(x1 >= 0);
+ Q_ASSERT(x2 < count);
+
+ int distx = (fx & 0x0000ffff) >> 8;
+ int idistx = 256 - distx;
+ int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff;
+ int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00;
+ *b++ = rb | ag;
+ fx += fdx;
+ }
+}
+
+
+typedef void (QT_FASTCALL *BilinearFastTransformFetcher)(uint *buf1, uint *buf2, const int len, const QTextureData &image,
+ int fx, int fy, const int fdx, const int fdy);
+
+template<TextureBlendType blendType, QPixelLayout::BPP bpp>
+static void QT_FASTCALL fetchTransformedBilinear_fetcher(uint *buf1, uint *buf2, const int len, const QTextureData &image,
+ int fx, int fy, const int fdx, const int fdy)
+{
+ const QPixelLayout &layout = qPixelLayouts[image.format];
+ Q_ASSERT(bpp == QPixelLayout::BPPNone || bpp == layout.bpp);
+ // When templated 'fetch1' should be inlined at compile time:
+ const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout.bpp] : fetchPixel<bpp>;
+ if (fdy == 0) {
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ const uchar *s1 = image.scanLine(y1);
+ const uchar *s2 = image.scanLine(y2);
+
+ int i = 0;
+ if (blendType == BlendTransformedBilinear) {
+ for (; i < len; ++i) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ if (x1 != x2)
+ break;
+ buf1[i * 2 + 0] = buf1[i * 2 + 1] = fetch1(s1, x1);
+ buf2[i * 2 + 0] = buf2[i * 2 + 1] = fetch1(s2, x1);
+ fx += fdx;
+ }
+ int fastLen = len;
+ if (fdx > 0)
+ fastLen = qMin(fastLen, int((qint64(image.x2 - 1) * fixed_scale - fx) / fdx));
+ else if (fdx < 0)
+ fastLen = qMin(fastLen, int((qint64(image.x1) * fixed_scale - fx) / fdx));
+
+ for (; i < fastLen; ++i) {
+ int x = (fx >> 16);
+ buf1[i * 2 + 0] = fetch1(s1, x);
+ buf1[i * 2 + 1] = fetch1(s1, x + 1);
+ buf2[i * 2 + 0] = fetch1(s2, x);
+ buf2[i * 2 + 1] = fetch1(s2, x + 1);
+ fx += fdx;
+ }
+ }
+
+ for (; i < len; ++i) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ buf1[i * 2 + 0] = fetch1(s1, x1);
+ buf1[i * 2 + 1] = fetch1(s1, x2);
+ buf2[i * 2 + 0] = fetch1(s2, x1);
+ buf2[i * 2 + 1] = fetch1(s2, x2);
+ fx += fdx;
+ }
+ } else {
+ int i = 0;
+ if (blendType == BlendTransformedBilinear) {
+ for (; i < len; ++i) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+ if (x1 != x2 && y1 != y2)
+ break;
+ const uchar *s1 = image.scanLine(y1);
+ const uchar *s2 = image.scanLine(y2);
+ buf1[i * 2 + 0] = fetch1(s1, x1);
+ buf1[i * 2 + 1] = fetch1(s1, x2);
+ buf2[i * 2 + 0] = fetch1(s2, x1);
+ buf2[i * 2 + 1] = fetch1(s2, x2);
+ fx += fdx;
+ fy += fdy;
+ }
+ int fastLen = len;
+ if (fdx > 0)
+ fastLen = qMin(fastLen, int((qint64(image.x2 - 1) * fixed_scale - fx) / fdx));
+ else if (fdx < 0)
+ fastLen = qMin(fastLen, int((qint64(image.x1) * fixed_scale - fx) / fdx));
+ if (fdy > 0)
+ fastLen = qMin(fastLen, int((qint64(image.y2 - 1) * fixed_scale - fy) / fdy));
+ else if (fdy < 0)
+ fastLen = qMin(fastLen, int((qint64(image.y1) * fixed_scale - fy) / fdy));
+
+ for (; i < fastLen; ++i) {
+ int x = (fx >> 16);
+ int y = (fy >> 16);
+ const uchar *s1 = image.scanLine(y);
+ const uchar *s2 = s1 + image.bytesPerLine;
+ buf1[i * 2 + 0] = fetch1(s1, x);
+ buf1[i * 2 + 1] = fetch1(s1, x + 1);
+ buf2[i * 2 + 0] = fetch1(s2, x);
+ buf2[i * 2 + 1] = fetch1(s2, x + 1);
+ fx += fdx;
+ fy += fdy;
+ }
+ }
+
+ for (; i < len; ++i) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
+
+ const uchar *s1 = image.scanLine(y1);
+ const uchar *s2 = image.scanLine(y2);
+ buf1[i * 2 + 0] = fetch1(s1, x1);
+ buf1[i * 2 + 1] = fetch1(s1, x2);
+ buf2[i * 2 + 0] = fetch1(s2, x1);
+ buf2[i * 2 + 1] = fetch1(s2, x2);
+ fx += fdx;
+ fy += fdy;
+ }
+ }
+}
+
// blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled
template<TextureBlendType blendType, QPixelLayout::BPP bpp>
static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *,
@@ -2665,19 +2912,7 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
{
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
const QVector<QRgb> *clut = data->texture.colorTable;
- if (bpp != QPixelLayout::BPPNone) // Like this to not ICE on GCC 5.3.1
- Q_ASSERT(layout->bpp == bpp);
- // When templated 'fetch' should be inlined at compile time:
- const FetchPixelsFunc fetch = (bpp == QPixelLayout::BPPNone) ? qFetchPixels[layout->bpp] : FetchPixelsFunc(fetchPixels<bpp>);
- const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : FetchPixelFunc(fetchPixel<bpp>);
-
- int image_width = data->texture.width;
- int image_height = data->texture.height;
-
- int image_x1 = data->texture.x1;
- int image_y1 = data->texture.y1;
- int image_x2 = data->texture.x2 - 1;
- int image_y2 = data->texture.y2 - 1;
+ Q_ASSERT(bpp == QPixelLayout::BPPNone || layout->bpp == bpp);
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
@@ -2693,203 +2928,80 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
fx -= half_point;
fy -= half_point;
- if (fdy == 0) { //simple scale, no rotation
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
-
- if (fdx <= fixed_scale && fdx > 0) { // scale up on X
- int disty = (fy & 0x0000ffff) >> 8;
- int idisty = 256 - disty;
- int x = fx >> 16;
-
- // The idea is first to do the interpolation between the row s1 and the row s2
- // into an intermediate buffer, then we interpolate between two pixel of this buffer.
- // +1 for the last pixel to interpolate with, and +1 for rounding errors.
- uint buf1[buffer_size + 2];
- uint buf2[buffer_size + 2];
- const uint *ptr1;
- const uint *ptr2;
-
- int count = (qint64(length) * fdx + fixed_scale - 1) / fixed_scale + 2;
- Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
-
- if (blendType == BlendTransformedBilinearTiled) {
- x %= image_width;
- if (x < 0)
- x += image_width;
- int len1 = qMin(count, image_width - x);
- int len2 = qMin(x, count - len1);
-
- ptr1 = fetch(buf1, s1, x, len1);
- ptr1 = layout->convertToARGB32PM(buf1, ptr1, len1, clut, 0);
- ptr2 = fetch(buf2, s2, x, len1);
- ptr2 = layout->convertToARGB32PM(buf2, ptr2, len1, clut, 0);
- for (int i = 0; i < len1; ++i) {
- uint t = ptr1[i];
- uint b = ptr2[i];
- buf1[i] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
- buf2[i] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
- }
-
- if (len2) {
- ptr1 = fetch(buf1 + len1, s1, 0, len2);
- ptr1 = layout->convertToARGB32PM(buf1 + len1, ptr1, len2, clut, 0);
- ptr2 = fetch(buf2 + len1, s2, 0, len2);
- ptr2 = layout->convertToARGB32PM(buf2 + len1, ptr2, len2, clut, 0);
- for (int i = 0; i < len2; ++i) {
- uint t = ptr1[i];
- uint b = ptr2[i];
- buf1[i + len1] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
- buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
- }
- }
- for (int i = image_width; i < count; ++i) {
- buf1[i] = buf1[i - image_width];
- buf2[i] = buf2[i - image_width];
- }
- } else {
- int start = qMax(x, image_x1);
- int end = qMin(x + count, image_x2 + 1);
- int len = qMax(1, end - start);
- int leading = start - x;
-
- ptr1 = fetch(buf1 + leading, s1, start, len);
- ptr1 = layout->convertToARGB32PM(buf1 + leading, ptr1, len, clut, 0);
- ptr2 = fetch(buf2 + leading, s2, start, len);
- ptr2 = layout->convertToARGB32PM(buf2 + leading, ptr2, len, clut, 0);
-
- for (int i = 0; i < len; ++i) {
- uint t = ptr1[i];
- uint b = ptr2[i];
- buf1[i + leading] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
- buf2[i + leading] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
- }
-
- for (int i = 0; i < leading; ++i) {
- buf1[i] = buf1[leading];
- buf2[i] = buf2[leading];
- }
- for (int i = leading + len; i < count; ++i) {
- buf1[i] = buf1[i - 1];
- buf2[i] = buf2[i - 1];
- }
- }
-
- // Now interpolate the values from the intermediate_buffer to get the final result.
- fx &= fixed_scale - 1;
- Q_ASSERT((fx >> 16) == 0);
- for (int i = 0; i < length; ++i) {
- int x1 = (fx >> 16);
- int x2 = x1 + 1;
- Q_ASSERT(x1 >= 0);
- Q_ASSERT(x2 < count);
-
- int distx = (fx & 0x0000ffff) >> 8;
- int idistx = 256 - distx;
- int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff;
- int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00;
- buffer[i] = rb | ag;
- fx += fdx;
- }
+ if (fdy == 0) { // simple scale, no rotation or shear
+ if (qAbs(fdx) <= fixed_scale) { // scale up on X
+ fetchTransformedBilinear_simple_upscale_helper<blendType, bpp>(buffer, buffer + length, data->texture, fx, fy, fdx, fdy);
} else {
+ const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>;
+
uint buf1[buffer_size];
uint buf2[buffer_size];
uint *b = buffer;
while (length) {
int len = qMin(length, buffer_size / 2);
- int fracX = fx;
- for (int i = 0; i < len; ++i) {
- int x1 = (fx >> 16);
- int x2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- buf1[i * 2 + 0] = fetch1(s1, x1);
- buf1[i * 2 + 1] = fetch1(s1, x2);
- buf2[i * 2 + 0] = fetch1(s2, x1);
- buf2[i * 2 + 1] = fetch1(s2, x2);
- fx += fdx;
- }
+ fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, 0);
layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0);
layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0);
- if ((fdx < 0 && fdx > -(fixed_scale / 8)) || qAbs(data->m22) < qreal(1./8.)) { // scale up more than 8x
+ if (qAbs(data->m22) < qreal(1./8.)) { // scale up more than 8x (on Y)
int disty = (fy & 0x0000ffff) >> 8;
for (int i = 0; i < len; ++i) {
- int distx = (fracX & 0x0000ffff) >> 8;
+ int distx = (fx & 0x0000ffff) >> 8;
b[i] = interpolate_4_pixels(buf1 + i * 2, buf2 + i * 2, distx, disty);
- fracX += fdx;
+ fx += fdx;
}
- } else { //scale down
+ } else {
int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
for (int i = 0; i < len; ++i) {
uint tl = buf1[i * 2 + 0];
uint tr = buf1[i * 2 + 1];
uint bl = buf2[i * 2 + 0];
uint br = buf2[i * 2 + 1];
- int distx = ((fracX & 0x0000ffff) + 0x0800) >> 12;
+ int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
- fracX += fdx;
+ fx += fdx;
}
}
length -= len;
b += len;
}
}
- } else { //rotation
+ } else { // rotation or shear
+ const BilinearFastTransformFetcher fetcher = fetchTransformedBilinear_fetcher<blendType,bpp>;
+
uint buf1[buffer_size];
uint buf2[buffer_size];
uint *b = buffer;
-
while (length) {
int len = qMin(length, buffer_size / 2);
- int fracX = fx;
- int fracY = fy;
- for (int i = 0; i < len; ++i) {
- int x1 = (fx >> 16);
- int x2;
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
-
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
- buf1[i * 2 + 0] = fetch1(s1, x1);
- buf1[i * 2 + 1] = fetch1(s1, x2);
- buf2[i * 2 + 0] = fetch1(s2, x1);
- buf2[i * 2 + 1] = fetch1(s2, x2);
- fx += fdx;
- fy += fdy;
- }
+ fetcher(buf1, buf2, len, data->texture, fx, fy, fdx, fdy);
layout->convertToARGB32PM(buf1, buf1, len * 2, clut, 0);
layout->convertToARGB32PM(buf2, buf2, len * 2, clut, 0);
- if (qAbs(data->m11) < qreal(1./8.) || qAbs(data->m22) < qreal(1./8.) ) {
- //if we are zooming more than 8 times, we use 8bit precision for the position.
+ if (qAbs(data->m11) < qreal(1./8.)|| qAbs(data->m22) < qreal(1./8.)) {
+ // If we are zooming more than 8 times, we use 8bit precision for the position.
for (int i = 0; i < len; ++i) {
- int distx = (fracX & 0x0000ffff) >> 8;
- int disty = (fracY & 0x0000ffff) >> 8;
+ int distx = (fx & 0x0000ffff) >> 8;
+ int disty = (fy & 0x0000ffff) >> 8;
b[i] = interpolate_4_pixels(buf1 + i * 2, buf2 + i * 2, distx, disty);
- fracX += fdx;
- fracY += fdy;
+ fx += fdx;
+ fy += fdy;
}
} else {
- //we are zooming less than 8x, use 4bit precision
+ // We are zooming less than 8x, use 4bit precision
for (int i = 0; i < len; ++i) {
uint tl = buf1[i * 2 + 0];
uint tr = buf1[i * 2 + 1];
uint bl = buf2[i * 2 + 0];
uint br = buf2[i * 2 + 1];
- int distx = ((fracX & 0x0000ffff) + 0x0800) >> 12;
- int disty = ((fracY & 0x0000ffff) + 0x0800) >> 12;
+ int distx = ((fx & 0x0000ffff) + 0x0800) >> 12;
+ int disty = ((fy & 0x0000ffff) + 0x0800) >> 12;
b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
- fracX += fdx;
- fracY += fdy;
+ fx += fdx;
+ fy += fdy;
}
}
@@ -2898,6 +3010,11 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
}
}
} else {
+ // When templated 'fetch' should be inlined at compile time:
+ const FetchPixelFunc fetch1 = (bpp == QPixelLayout::BPPNone) ? qFetchPixel[layout->bpp] : fetchPixel<bpp>;
+
+ const QTextureData &image = data->texture;
+
const qreal fdx = data->m11;
const qreal fdy = data->m12;
const qreal fdw = data->m13;
@@ -2928,8 +3045,8 @@ static const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Oper
distxs[i] = int((px - x1) * 256);
distys[i] = int((py - y1) * 256);
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
const uchar *s1 = data->texture.scanLine(y1);
const uchar *s2 = data->texture.scanLine(y2);
@@ -2970,21 +3087,9 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
const QVector<QRgb> *clut = data->texture.colorTable;
- int image_width = data->texture.width;
- int image_height = data->texture.height;
-
- int image_x1 = data->texture.x1;
- int image_y1 = data->texture.y1;
- int image_x2 = data->texture.x2 - 1;
- int image_y2 = data->texture.y2 - 1;
-
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
- const qreal fdx = data->m11;
- const qreal fdy = data->m12;
- const qreal fdw = data->m13;
-
if (data->fast_matrix) {
// The increment pr x in the scanline
int fdx = (int)(data->m11 * fixed_scale);
@@ -2996,14 +3101,13 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
fx -= half_point;
fy -= half_point;
+ const BilinearFastTransformFetcher fetcher =
+ (layout->bpp == QPixelLayout::BPP32)
+ ? fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPP32>
+ : fetchTransformedBilinear_fetcher<blendType, QPixelLayout::BPPNone>;
+
if (fdy == 0) { //simple scale, no rotation
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
- FetchPixelFunc fetch = qFetchPixel[layout->bpp];
uint sbuf1[buffer_size];
uint sbuf2[buffer_size];
quint64 buf1[buffer_size];
@@ -3011,84 +3115,19 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
QRgba64 *b = buffer;
while (length) {
int len = qMin(length, buffer_size / 2);
- int fracX = fx;
- int i = 0;
int disty = (fy & 0x0000ffff);
#if defined(__SSE2__)
const __m128i vdy = _mm_set1_epi16(disty);
const __m128i vidy = _mm_set1_epi16(0x10000 - disty);
- if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) {
- for (; i < len; ++i) {
- int x1 = (fx >> 16);
- int x2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- if (x1 != x2)
- break;
- sbuf1[i * 2 + 0] = sbuf1[i * 2 + 1] = ((const uint*)s1)[x1];
- sbuf2[i * 2 + 0] = sbuf2[i * 2 + 1] = ((const uint*)s2)[x1];
- fx += fdx;
- }
- int fastLen;
- if (fdx > 0)
- fastLen = qMin(len, int((image_x2 - (fx >> 16)) / data->m11));
- else
- fastLen = qMin(len, int((image_x1 - (fx >> 16)) / data->m11));
- fastLen -= 3;
-
- const __m128i v_fdx = _mm_set1_epi32(fdx*4);
- __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
- for (; i < fastLen; i += 4) {
- int offset = _mm_extract_epi16(v_fx, 1);
- sbuf1[i * 2 + 0] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 0] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1];
- offset = _mm_extract_epi16(v_fx, 3);
- sbuf1[i * 2 + 2] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 2] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1];
- offset = _mm_extract_epi16(v_fx, 5);
- sbuf1[i * 2 + 4] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 4] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1];
- offset = _mm_extract_epi16(v_fx, 7);
- sbuf1[i * 2 + 6] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 6] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1];
- v_fx = _mm_add_epi32(v_fx, v_fdx);
- }
- fx = _mm_cvtsi128_si32(v_fx);
- }
#endif
- for (; i < len; ++i) {
- int x1 = (fx >> 16);
- int x2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
-
- if (layout->bpp == QPixelLayout::BPP32) {
- sbuf1[i * 2 + 0] = ((const uint*)s1)[x1];
- sbuf1[i * 2 + 1] = ((const uint*)s1)[x2];
- sbuf2[i * 2 + 0] = ((const uint*)s2)[x1];
- sbuf2[i * 2 + 1] = ((const uint*)s2)[x2];
-
- } else {
- sbuf1[i * 2 + 0] = fetch(s1, x1);
- sbuf1[i * 2 + 1] = fetch(s1, x2);
- sbuf2[i * 2 + 0] = fetch(s2, x1);
- sbuf2[i * 2 + 1] = fetch(s2, x2);
- }
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
- fx += fdx;
- }
layout->convertToARGB64PM((QRgba64 *)buf1, sbuf1, len * 2, clut, 0);
if (disty)
layout->convertToARGB64PM((QRgba64 *)buf2, sbuf2, len * 2, clut, 0);
for (int i = 0; i < len; ++i) {
- int distx = (fracX & 0x0000ffff);
+ int distx = (fx & 0x0000ffff);
#if defined(__SSE2__)
__m128i vt = _mm_loadu_si128((const __m128i*)(buf1 + i*2));
if (disty) {
@@ -3107,13 +3146,12 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
#else
b[i] = interpolate_4_pixels_rgb64((QRgba64 *)buf1 + i*2, (QRgba64 *)buf2 + i*2, distx, disty);
#endif
- fracX += fdx;
+ fx += fdx;
}
length -= len;
b += len;
}
} else { //rotation
- FetchPixelFunc fetch = qFetchPixel[layout->bpp];
uint sbuf1[buffer_size];
uint sbuf2[buffer_size];
quint64 buf1[buffer_size];
@@ -3123,117 +3161,18 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
while (b < end) {
int len = qMin(length, buffer_size / 2);
- int fracX = fx;
- int fracY = fy;
- int i = 0;
-#if defined(__SSE2__)
- if (blendType != BlendTransformedBilinearTiled && layout->bpp == QPixelLayout::BPP32) {
- for (; i < len; ++i) {
- int x1 = (fx >> 16);
- int x2;
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- if (x1 != x2 && y1 != y2)
- break;
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
- sbuf1[i * 2 + 0] = ((const uint*)s1)[x1];
- sbuf1[i * 2 + 1] = ((const uint*)s1)[x2];
- sbuf2[i * 2 + 0] = ((const uint*)s2)[x1];
- sbuf2[i * 2 + 1] = ((const uint*)s2)[x2];
- fx += fdx;
- fy += fdy;
- }
- int fastLen = len;
- if (fdx > 0)
- fastLen = qMin(fastLen, int((qint64(image_x2) * fixed_scale - fx) / fdx));
- else if (fdx < 0)
- fastLen = qMin(fastLen, int((qint64(image_x1) * fixed_scale - fx) / fdx));
- if (fdy > 0)
- fastLen = qMin(fastLen, int((qint64(image_y2) * fixed_scale - fy) / fdy));
- else if (fdy < 0)
- fastLen = qMin(fastLen, int((qint64(image_y1) * fixed_scale - fy) / fdy));
- fastLen -= 3;
-
- const __m128i v_fdx = _mm_set1_epi32(fdx*4);
- const __m128i v_fdy = _mm_set1_epi32(fdy*4);
- __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx);
- __m128i v_fy = _mm_setr_epi32(fy, fy + fdy, fy + fdy + fdy, fy + fdy + fdy + fdy);
- const int bytesPerLine = data->texture.bytesPerLine;
- const uchar *s1 = data->texture.imageData;
- const uchar *s2 = s1 + bytesPerLine;
- const __m128i vbpl = _mm_shufflelo_epi16(_mm_cvtsi32_si128(bytesPerLine/4), _MM_SHUFFLE(0, 0, 0, 0));
- for (; i < fastLen; i += 4) {
- const __m128i vy = _mm_packs_epi32(_mm_srai_epi32(v_fy, 16), _mm_setzero_si128());
- __m128i voffset = _mm_unpacklo_epi16(_mm_mullo_epi16(vy, vbpl), _mm_mulhi_epu16(vy, vbpl));
- voffset = _mm_add_epi32(voffset, _mm_srli_epi32(v_fx, 16));
-
- int offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4);
- sbuf1[i * 2 + 0] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 0] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 1] = ((const uint*)s2)[offset + 1];
- offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4);
- sbuf1[i * 2 + 2] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 3] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 2] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 3] = ((const uint*)s2)[offset + 1];
- offset = _mm_cvtsi128_si32(voffset); voffset = _mm_srli_si128(voffset, 4);
- sbuf1[i * 2 + 4] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 5] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 4] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 5] = ((const uint*)s2)[offset + 1];
- offset = _mm_cvtsi128_si32(voffset);
- sbuf1[i * 2 + 6] = ((const uint*)s1)[offset];
- sbuf1[i * 2 + 7] = ((const uint*)s1)[offset + 1];
- sbuf2[i * 2 + 6] = ((const uint*)s2)[offset];
- sbuf2[i * 2 + 7] = ((const uint*)s2)[offset + 1];
-
- v_fx = _mm_add_epi32(v_fx, v_fdx);
- v_fy = _mm_add_epi32(v_fy, v_fdy);
- }
- fx = _mm_cvtsi128_si32(v_fx);
- fy = _mm_cvtsi128_si32(v_fy);
- }
-#endif
- for (; i < len; ++i) {
- int x1 = (fx >> 16);
- int x2;
- int y1 = (fy >> 16);
- int y2;
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
-
- if (layout->bpp == QPixelLayout::BPP32) {
- sbuf1[i * 2 + 0] = ((const uint*)s1)[x1];
- sbuf1[i * 2 + 1] = ((const uint*)s1)[x2];
- sbuf2[i * 2 + 0] = ((const uint*)s2)[x1];
- sbuf2[i * 2 + 1] = ((const uint*)s2)[x2];
-
- } else {
- sbuf1[i * 2 + 0] = fetch(s1, x1);
- sbuf1[i * 2 + 1] = fetch(s1, x2);
- sbuf2[i * 2 + 0] = fetch(s2, x1);
- sbuf2[i * 2 + 1] = fetch(s2, x2);
- }
+ fetcher(sbuf1, sbuf2, len, data->texture, fx, fy, fdx, fdy);
- fx += fdx;
- fy += fdy;
- }
layout->convertToARGB64PM((QRgba64 *)buf1, sbuf1, len * 2, clut, 0);
layout->convertToARGB64PM((QRgba64 *)buf2, sbuf2, len * 2, clut, 0);
for (int i = 0; i < len; ++i) {
- int distx = (fracX & 0x0000ffff);
- int disty = (fracY & 0x0000ffff);
+ int distx = (fx & 0x0000ffff);
+ int disty = (fy & 0x0000ffff);
b[i] = interpolate_4_pixels_rgb64((QRgba64 *)buf1 + i*2, (QRgba64 *)buf2 + i*2, distx, disty);
- fracX += fdx;
- fracY += fdy;
+ fx += fdx;
+ fy += fdy;
}
length -= len;
@@ -3241,6 +3180,12 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
}
}
} else {
+ const QTextureData &image = data->texture;
+
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
@@ -3270,8 +3215,8 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co
distxs[i] = int((px - x1) * (1<<16));
distys[i] = int((py - y1) * (1<<16));
- fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.width, image.x1, image.x2 - 1, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image.height, image.y1, image.y2 - 1, y1, y2);
const uchar *s1 = data->texture.scanLine(y1);
const uchar *s2 = data->texture.scanLine(y2);
@@ -3842,7 +3787,7 @@ void blend_color_generic_rgb64(int count, const QSpan *spans, void *userData)
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
Operator op = getOperator(data, spans, count);
if (!op.funcSolid64) {
- qDebug("unsupported 64bit blend attempted");
+ qCDebug(lcQtGuiDrawHelper, "blend_color_generic_rgb64: unsupported 64bit blend attempted, falling back to 32-bit");
return blend_color_generic(count, spans, userData);
}
@@ -4080,7 +4025,7 @@ static void blend_src_generic_rgb64(int count, const QSpan *spans, void *userDat
if (blend64.isSupported())
handleSpans(count, spans, data, blend64);
else {
- qDebug("blend_src_generic_rgb64: unsupported 64-bit blend attempted");
+ qCDebug(lcQtGuiDrawHelper, "blend_src_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
BlendSrcGeneric blend32(data, op);
handleSpans(count, spans, data, blend32);
}
@@ -4137,7 +4082,7 @@ static void blend_untransformed_generic_rgb64(int count, const QSpan *spans, voi
Operator op = getOperator(data, spans, count);
if (!op.func64) {
- qWarning("Unsupported blend");
+ qCDebug(lcQtGuiDrawHelper, "blend_untransformed_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
return blend_untransformed_generic(count, spans, userData);
}
quint64 buffer[buffer_size];
@@ -4378,7 +4323,7 @@ static void blend_tiled_generic_rgb64(int count, const QSpan *spans, void *userD
Operator op = getOperator(data, spans, count);
if (!op.func64) {
- qDebug("unsupported rgb64 blend");
+ qCDebug(lcQtGuiDrawHelper, "blend_tiled_generic_rgb64: unsupported 64-bit blend attempted, falling back to 32-bit");
return blend_tiled_generic(count, spans, userData);
}
quint64 buffer[buffer_size];
@@ -4774,6 +4719,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData
CompositionFunction func = functionForMode[data->rasterBuffer->compositionMode];
uint buffer[buffer_size];
+ quint32 mask = (data->texture.format == QImage::Format_RGB32) ? 0xff000000 : 0;
const int image_x1 = data->texture.x1;
const int image_y1 = data->texture.y1;
@@ -4807,7 +4753,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData
while (b < end) {
int px = qBound(image_x1, x >> 16, image_x2);
int py = qBound(image_y1, y >> 16, image_y2);
- *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
+ *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px] | mask;
x += fdx;
y += fdy;
@@ -4848,7 +4794,7 @@ static void blend_transformed_argb(int count, const QSpan *spans, void *userData
const int px = qBound(image_x1, int(tx) - (tx < 0), image_x2);
const int py = qBound(image_y1, int(ty) - (ty < 0), image_y2);
- *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
+ *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px] | mask;
x += fdx;
y += fdy;
w += fdw;
@@ -5014,7 +4960,7 @@ static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *us
int image_width = data->texture.width;
int image_height = data->texture.height;
- const int scanline_offset = data->texture.bytesPerLine / 4;
+ const qsizetype scanline_offset = data->texture.bytesPerLine / 4;
if (data->fast_matrix) {
// The increment pr x in the scanline
@@ -5354,7 +5300,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
int mapWidth, int mapHeight, int mapStride)
{
DST *dest = reinterpret_cast<DST *>(rasterBuffer->scanLine(y)) + x;
- const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
+ const int destStride = rasterBuffer->stride<DST>();
if (mapWidth > 8) {
while (mapHeight--) {
@@ -5670,7 +5616,7 @@ void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
if (!clip) {
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
- const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
+ const int destStride = rasterBuffer->stride<quint16>();
while (mapHeight--) {
for (int i = 0; i < mapWidth; ++i)
alphamapblend_quint16(map[i], dest, i, c);
@@ -5745,7 +5691,7 @@ static void qt_alphamapblit_argb32(QRasterBuffer *rasterBuffer,
const QClipData *clip, bool useGammaCorrection)
{
const quint32 c = color.toArgb32();
- const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
+ const int destStride = rasterBuffer->stride<quint32>();
if (color.isTransparent())
return;
@@ -5943,7 +5889,7 @@ static void qt_alphargbblit_argb32(QRasterBuffer *rasterBuffer,
if (!clip) {
quint32 *dst = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
- const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
+ const int destStride = rasterBuffer->stride<quint32>();
while (mapHeight--) {
for (int i = 0; i < mapWidth; ++i) {
const uint coverage = src[i];
diff --git a/src/gui/painting/qdrawhelper_avx2.cpp b/src/gui/painting/qdrawhelper_avx2.cpp
index a7e03a7bb3..2619539788 100644
--- a/src/gui/painting/qdrawhelper_avx2.cpp
+++ b/src/gui/painting/qdrawhelper_avx2.cpp
@@ -420,10 +420,14 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
const uint *s1 = (const uint *)image.scanLine(y1);
const uint *s2 = (const uint *)image.scanLine(y2);
- int disty = (fy & 0x0000ffff) >> 8;
- int idisty = 256 - disty;
- int x = fx >> 16;
- int length = end - b;
+ const int disty = (fy & 0x0000ffff) >> 8;
+ const int idisty = 256 - disty;
+ const int length = end - b;
+
+ // The intermediate buffer is generated in the positive direction
+ const int adjust = (fdx < 0) ? fdx * length : 0;
+ const int offset = (fx + adjust) >> 16;
+ int x = offset;
// The idea is first to do the interpolation between the row s1 and the row s2
// into an intermediate buffer, then we interpolate between two pixel of this buffer.
@@ -433,7 +437,7 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
// +1 for the last pixel to interpolate with, and +1 for rounding errors.
quint32 intermediate_buffer[2][BufferSize + 2];
// count is the size used in the intermediate_buffer.
- int count = (qint64(length) * fdx + FixedScale - 1) / FixedScale + 2;
+ int count = (qint64(length) * qAbs(fdx) + FixedScale - 1) / FixedScale + 2;
Q_ASSERT(count <= BufferSize + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
int f = 0;
int lim = qMin(count, image.x2 - x);
@@ -492,8 +496,7 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_simple_upscale_helper_avx2(uin
x++;
}
// Now interpolate the values from the intermediate_buffer to get the final result.
- fx &= FixedScale - 1;
- Q_ASSERT((fx >> 16) == 0);
+ fx -= offset * FixedScale;
const __m128i v_fdx = _mm_set1_epi32(fdx * 4);
const __m128i v_blend = _mm_set1_epi32(0x00800080);
@@ -682,7 +685,7 @@ void QT_FASTCALL fetchTransformedBilinearARGB32PM_fast_rotate_helper_avx2(uint *
v_fy = _mm256_add_epi32(v_fy, _mm256_mullo_epi32(_mm256_set1_epi32(fdy), v_index));
const uchar *textureData = image.imageData;
- const int bytesPerLine = image.bytesPerLine;
+ const qsizetype bytesPerLine = image.bytesPerLine;
const __m256i vbpl = _mm256_set1_epi16(bytesPerLine/4);
while (b < boundedEnd - 7) {
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index ccfc9a2889..df9f762314 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -293,7 +293,7 @@ struct QTextureData
int y1;
int x2;
int y2;
- int bytesPerLine;
+ qsizetype bytesPerLine;
QImage::Format format;
const QVector<QRgb> *colorTable;
bool hasAlpha;
@@ -847,7 +847,7 @@ inline void qt_memfill(T *dest, T value, int count)
template <class T> Q_STATIC_TEMPLATE_FUNCTION
inline void qt_rectfill(T *dest, T value,
- int x, int y, int width, int height, int stride)
+ int x, int y, int width, int height, qsizetype stride)
{
char *d = reinterpret_cast<char*>(dest + x) + y * stride;
if (uint(stride) == (width * sizeof(T))) {
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 3013d2cf3e..bfe2080298 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -341,7 +341,7 @@ void qt_bitmapblit32_sse2_base(QRasterBuffer *rasterBuffer, int x, int y,
const uchar *src, int width, int height, int stride)
{
quint32 *dest = reinterpret_cast<quint32*>(rasterBuffer->scanLine(y)) + x;
- const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint32);
+ const int destStride = rasterBuffer->stride<quint32>();
const __m128i c128 = _mm_set1_epi32(color);
const __m128i maskmask1 = _mm_set_epi32(0x10101010, 0x20202020,
@@ -407,7 +407,7 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y,
{
const quint16 c = qConvertRgb32To16(color.toArgb32());
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
- const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
+ const int destStride = rasterBuffer->stride<quint32>();
const __m128i c128 = _mm_set1_epi16(c);
QT_WARNING_DISABLE_MSVC(4309) // truncation of constant value
diff --git a/src/gui/painting/qemulationpaintengine.cpp b/src/gui/painting/qemulationpaintengine.cpp
index 586b71557e..e6686e3721 100644
--- a/src/gui/painting/qemulationpaintengine.cpp
+++ b/src/gui/painting/qemulationpaintengine.cpp
@@ -72,6 +72,14 @@ QPainterState *QEmulationPaintEngine::createState(QPainterState *orig) const
return real_engine->createState(orig);
}
+static inline void combineXForm(QBrush *brush, const QRectF &r)
+{
+ QTransform t = brush->transform();
+ t.translate(r.x(), r.y());
+ t.scale(r.width(), r.height());
+ brush->setTransform(t);
+}
+
void QEmulationPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
{
QPainterState *s = state();
@@ -84,26 +92,14 @@ void QEmulationPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
Qt::BrushStyle style = qbrush_style(brush);
if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
- const QGradient *g = brush.gradient();
-
- if (g->coordinateMode() > QGradient::LogicalMode) {
- if (g->coordinateMode() == QGradient::StretchToDeviceMode) {
- QBrush copy = brush;
- QTransform mat = copy.transform();
- mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height());
- copy.setTransform(mat);
- real_engine->fill(path, copy);
- return;
- } else if (g->coordinateMode() == QGradient::ObjectBoundingMode) {
- QBrush copy = brush;
- QTransform mat = copy.transform();
- QRectF r = path.controlPointRect();
- mat.translate(r.x(), r.y());
- mat.scale(r.width(), r.height());
- copy.setTransform(mat);
- real_engine->fill(path, copy);
- return;
- }
+ QGradient::CoordinateMode coMode = brush.gradient()->coordinateMode();
+ if (coMode > QGradient::LogicalMode) {
+ QBrush copy = brush;
+ const QPaintDevice *d = real_engine->painter()->device();
+ QRectF r = (coMode == QGradient::ObjectBoundingMode) ? path.controlPointRect() : QRectF(0, 0, d->width(), d->height());
+ combineXForm(&copy, r);
+ real_engine->fill(path, copy);
+ return;
}
}
@@ -124,27 +120,15 @@ void QEmulationPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
QBrush brush = pen.brush();
QPen copy = pen;
Qt::BrushStyle style = qbrush_style(brush);
- if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) {
- const QGradient *g = brush.gradient();
-
- if (g->coordinateMode() > QGradient::LogicalMode) {
- if (g->coordinateMode() == QGradient::StretchToDeviceMode) {
- QTransform mat = brush.transform();
- mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height());
- brush.setTransform(mat);
- copy.setBrush(brush);
- real_engine->stroke(path, copy);
- return;
- } else if (g->coordinateMode() == QGradient::ObjectBoundingMode) {
- QTransform mat = brush.transform();
- QRectF r = path.controlPointRect();
- mat.translate(r.x(), r.y());
- mat.scale(r.width(), r.height());
- brush.setTransform(mat);
- copy.setBrush(brush);
- real_engine->stroke(path, copy);
- return;
- }
+ if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern ) {
+ QGradient::CoordinateMode coMode = brush.gradient()->coordinateMode();
+ if (coMode > QGradient::LogicalMode) {
+ const QPaintDevice *d = real_engine->painter()->device();
+ QRectF r = (coMode == QGradient::ObjectBoundingMode) ? path.controlPointRect() : QRectF(0, 0, d->width(), d->height());
+ combineXForm(&brush, r);
+ copy.setBrush(brush);
+ real_engine->stroke(path, copy);
+ return;
}
}
@@ -179,18 +163,16 @@ void QEmulationPaintEngine::drawTextItem(const QPointF &p, const QTextItem &text
QGradient g = *s->pen.brush().gradient();
if (g.coordinateMode() > QGradient::LogicalMode) {
- QTransform mat = s->pen.brush().transform();
- if (g.coordinateMode() == QGradient::StretchToDeviceMode) {
- mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height());
- } else if (g.coordinateMode() == QGradient::ObjectBoundingMode) {
- const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
- QRectF r(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal());
- mat.translate(r.x(), r.y());
- mat.scale(r.width(), r.height());
- }
+ QBrush copy = s->pen.brush();
+ const QPaintDevice *d = real_engine->painter()->device();
+ const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
+ QRectF r = (g.coordinateMode() == QGradient::ObjectBoundingMode) ?
+ QRectF(p.x(), p.y() - ti.ascent.toReal(), ti.width.toReal(), (ti.ascent + ti.descent + 1).toReal()) :
+ QRectF(0, 0, d->width(), d->height());
+ combineXForm(&copy, r);
g.setCoordinateMode(QGradient::LogicalMode);
QBrush brush(g);
- brush.setTransform(mat);
+ brush.setTransform(copy.transform());
s->pen.setBrush(brush);
penChanged();
real_engine->drawTextItem(p, textItem);
diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.c
index 4a135e25d8..0143e9b602 100644
--- a/src/gui/painting/qgrayraster.c
+++ b/src/gui/painting/qgrayraster.c
@@ -43,7 +43,7 @@
/* */
/* A new `perfect' anti-aliasing renderer (body). */
/* */
-/* Copyright 2000-2001, 2002, 2003 by */
+/* Copyright 2000-2016 by */
/* David Turner, Robert Wilhelm, and Werner Lemberg. */
/* */
/* This file is part of the FreeType project, and may only be used, */
@@ -119,10 +119,6 @@
/* */
/*************************************************************************/
-/* experimental support for gamma correction within the rasterizer */
-#define xxxGRAYS_USE_GAMMA
-
-
/*************************************************************************/
/* */
/* The macro QT_FT_COMPONENT is used in trace mode. It is an implicit */
@@ -133,6 +129,28 @@
#define QT_FT_COMPONENT trace_smooth
+/* Auxiliary macros for token concatenation. */
+#define QT_FT_ERR_XCAT( x, y ) x ## y
+#define QT_FT_ERR_CAT( x, y ) QT_FT_ERR_XCAT( x, y )
+
+#define QT_FT_BEGIN_STMNT do {
+#define QT_FT_END_STMNT } while ( 0 )
+
+#define QT_FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) )
+#define QT_FT_ABS( a ) ( (a) < 0 ? -(a) : (a) )
+
+
+/*
+ * Approximate sqrt(x*x+y*y) using the `alpha max plus beta min'
+ * algorithm. We use alpha = 1, beta = 3/8, giving us results with a
+ * largest error less than 7% compared to the exact value.
+ */
+#define QT_FT_HYPOT( x, y ) \
+ ( x = QT_FT_ABS( x ), \
+ y = QT_FT_ABS( y ), \
+ x > y ? x + ( 3 * y >> 3 ) \
+ : y + ( 3 * x >> 3 ) )
+
#define ErrRaster_MemoryOverflow -4
#if defined(VXWORKS)
@@ -150,6 +168,9 @@
#define qt_ft_longjmp longjmp
#define qt_ft_jmp_buf jmp_buf
+#include <stddef.h>
+typedef ptrdiff_t QT_FT_PtrDist;
+
#define ErrRaster_Invalid_Mode -2
#define ErrRaster_Invalid_Outline -1
#define ErrRaster_Invalid_Argument -3
@@ -169,15 +190,10 @@
#define QT_FT_UNUSED( x ) (void) x
- /* Disable the tracing mechanism for simplicity -- developers can */
- /* activate it easily by redefining these two macros. */
-#ifndef QT_FT_ERROR
-#define QT_FT_ERROR( x ) do ; while ( 0 ) /* nothing */
-#endif
-
-#ifndef QT_FT_TRACE
-#define QT_FT_TRACE( x ) do ; while ( 0 ) /* nothing */
-#endif
+#define QT_FT_TRACE5( x ) do { } while ( 0 ) /* nothing */
+#define QT_FT_TRACE7( x ) do { } while ( 0 ) /* nothing */
+#define QT_FT_ERROR( x ) do { } while ( 0 ) /* nothing */
+#define QT_FT_THROW( e ) QT_FT_ERR_CAT( ErrRaster_, e )
#ifndef QT_FT_MEM_SET
#define QT_FT_MEM_SET( d, s, c ) qt_ft_memset( d, s, c )
@@ -187,9 +203,6 @@
#define QT_FT_MEM_ZERO( dest, count ) QT_FT_MEM_SET( dest, 0, count )
#endif
- /* define this to dump debugging information */
-#define xxxDEBUG_GRAYS
-
#define RAS_ARG PWorker worker
#define RAS_ARG_ PWorker worker,
@@ -199,26 +212,47 @@
#define ras (*worker)
-
/* must be at least 6 bits! */
#define PIXEL_BITS 8
#define ONE_PIXEL ( 1L << PIXEL_BITS )
-#define PIXEL_MASK ( -1L << PIXEL_BITS )
#define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) )
-#define SUBPIXELS( x ) ( (TPos)(x) * ( 1 << PIXEL_BITS ) )
+#define SUBPIXELS( x ) ( (TPos)(x) * ONE_PIXEL )
#define FLOOR( x ) ( (x) & -ONE_PIXEL )
#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
#if PIXEL_BITS >= 6
-#define UPSCALE( x ) ( (x) * ( 1 << ( PIXEL_BITS - 6 ) ) )
+#define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) )
#define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) )
#else
#define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) )
-#define DOWNSCALE( x ) ( (x) << ( 6 - PIXEL_BITS ) )
+#define DOWNSCALE( x ) ( (x) * ( 64 >> PIXEL_BITS ) )
#endif
+/* Compute `dividend / divisor' and return both its quotient and */
+/* remainder, cast to a specific type. This macro also ensures that */
+/* the remainder is always positive. */
+#define QT_FT_DIV_MOD( type, dividend, divisor, quotient, remainder ) \
+QT_FT_BEGIN_STMNT \
+ (quotient) = (type)( (dividend) / (divisor) ); \
+ (remainder) = (type)( (dividend) % (divisor) ); \
+ if ( (remainder) < 0 ) \
+ { \
+ (quotient)--; \
+ (remainder) += (type)(divisor); \
+ } \
+QT_FT_END_STMNT
+
+ /* These macros speed up repetitive divisions by replacing them */
+ /* with multiplications and right shifts. */
+#define QT_FT_UDIVPREP( b ) \
+ long b ## _r = (long)( ULONG_MAX >> PIXEL_BITS ) / ( b )
+#define QT_FT_UDIV( a, b ) \
+ ( ( (unsigned long)( a ) * (unsigned long)( b ## _r ) ) >> \
+ ( sizeof( long ) * CHAR_BIT - PIXEL_BITS ) )
+
+
/*************************************************************************/
/* */
/* TYPE DEFINITIONS */
@@ -228,28 +262,9 @@
/* need to define them to "float" or "double" when experimenting with */
/* new algorithms */
- typedef int TCoord; /* integer scanline/pixel coordinate */
- typedef int TPos; /* sub-pixel coordinate */
-
- /* determine the type used to store cell areas. This normally takes at */
- /* least PIXEL_BITS*2 + 1 bits. On 16-bit systems, we need to use */
- /* `long' instead of `int', otherwise bad things happen */
-
-#if PIXEL_BITS <= 7
-
- typedef int TArea;
-
-#else /* PIXEL_BITS >= 8 */
-
- /* approximately determine the size of integers using an ANSI-C header */
-#if QT_FT_UINT_MAX == 0xFFFFU
- typedef long TArea;
-#else
- typedef int TArea;
-#endif
-
-#endif /* PIXEL_BITS >= 8 */
-
+ typedef long TCoord; /* integer scanline/pixel coordinate */
+ typedef long TPos; /* sub-pixel coordinate */
+ typedef long TArea ; /* cell areas, coordinate products */
/* maximal number of gray spans in a call to the span callback */
#define QT_FT_MAX_GRAY_SPANS 256
@@ -279,17 +294,11 @@
int invalid;
PCell cells;
- int max_cells;
- int num_cells;
+ QT_FT_PtrDist max_cells;
+ QT_FT_PtrDist num_cells;
- TCoord cx, cy;
TPos x, y;
- TPos last_ey;
-
- QT_FT_Vector bez_stack[32 * 3 + 1];
- int lev_stack[32];
-
QT_FT_Outline outline;
QT_FT_Bitmap target;
QT_FT_BBox clip_box;
@@ -302,8 +311,6 @@
int band_size;
int band_shoot;
- int conic_level;
- int cubic_level;
qt_ft_jmp_buf jump_buffer;
@@ -311,7 +318,7 @@
long buffer_size;
PCell* ycells;
- int ycount;
+ TPos ycount;
int skip_spans;
} TWorker, *PWorker;
@@ -341,7 +348,7 @@
/* */
static void
gray_init_cells( RAS_ARG_ void* buffer,
- long byte_size )
+ long byte_size )
{
ras.buffer = buffer;
ras.buffer_size = byte_size;
@@ -404,31 +411,25 @@
/* */
/* Record the current cell in the table. */
/* */
- static void
- gray_record_cell( RAS_ARG )
+ static PCell
+ gray_find_cell( RAS_ARG )
{
PCell *pcell, cell;
- int x = ras.ex;
+ TPos x = ras.ex;
- if ( ras.invalid || !( ras.area | ras.cover ) )
- return;
- if ( x > ras.max_ex )
- x = ras.max_ex;
+ if ( x > ras.count_ex )
+ x = ras.count_ex;
pcell = &ras.ycells[ras.ey];
-
for (;;)
{
cell = *pcell;
if ( cell == NULL || cell->x > x )
break;
- if ( cell->x == x ) {
- cell->area += ras.area;
- cell->cover += ras.cover;
- return;
- }
+ if ( cell->x == x )
+ goto Exit;
pcell = &cell->next;
}
@@ -438,11 +439,28 @@
cell = ras.cells + ras.num_cells++;
cell->x = x;
- cell->area = ras.area;
- cell->cover = ras.cover;
+ cell->area = 0;
+ cell->cover = 0;
cell->next = *pcell;
*pcell = cell;
+
+ Exit:
+ return cell;
+ }
+
+
+ static void
+ gray_record_cell( RAS_ARG )
+ {
+ if ( ras.area | ras.cover )
+ {
+ PCell cell = gray_find_cell( RAS_VAR );
+
+
+ cell->area += ras.area;
+ cell->cover += ras.cover;
+ }
}
@@ -488,8 +506,8 @@
ras.ey = ey;
}
- ras.invalid = ( (unsigned)ey >= (unsigned)ras.count_ey ||
- ex >= ras.count_ex );
+ ras.invalid = ( (unsigned int)ey >= (unsigned int)ras.count_ey ||
+ ex >= ras.count_ex );
}
@@ -511,12 +529,13 @@
ras.cover = 0;
ras.ex = ex - ras.min_ex;
ras.ey = ey - ras.min_ey;
- ras.last_ey = SUBPIXELS( ey );
ras.invalid = 0;
gray_set_cell( RAS_VAR_ ex, ey );
}
+// The new render-line implementation is not yet used
+#if 1
/*************************************************************************/
/* */
@@ -529,9 +548,9 @@
TPos x2,
TCoord y2 )
{
- TCoord ex1, ex2, fx1, fx2, delta;
+ TCoord ex1, ex2, fx1, fx2, delta, mod;
int p, first, dx;
- int incr, lift, mod, rem;
+ int incr;
dx = x2 - x1;
@@ -573,13 +592,7 @@
dx = -dx;
}
- delta = (TCoord)( p / dx );
- mod = (TCoord)( p % dx );
- if ( mod < 0 )
- {
- delta--;
- mod += (TCoord)dx;
- }
+ QT_FT_DIV_MOD( TCoord, p, dx, delta, mod );
ras.area += (TArea)( fx1 + first ) * delta;
ras.cover += delta;
@@ -590,14 +603,11 @@
if ( ex1 != ex2 )
{
- p = ONE_PIXEL * ( y2 - y1 + delta );
- lift = (TCoord)( p / dx );
- rem = (TCoord)( p % dx );
- if ( rem < 0 )
- {
- lift--;
- rem += (TCoord)dx;
- }
+ TCoord lift, rem;
+
+
+ p = ONE_PIXEL * ( y2 - y1 + delta );
+ QT_FT_DIV_MOD( TCoord, p, dx, lift, rem );
mod -= (int)dx;
@@ -633,38 +643,24 @@
gray_render_line( RAS_ARG_ TPos to_x,
TPos to_y )
{
- TCoord ey1, ey2, fy1, fy2;
+ TCoord ey1, ey2, fy1, fy2, mod;
TPos dx, dy, x, x2;
int p, first;
- int delta, rem, mod, lift, incr;
+ int delta, rem, lift, incr;
- ey1 = TRUNC( ras.last_ey );
+ ey1 = TRUNC( ras.y );
ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
- fy1 = (TCoord)( ras.y - ras.last_ey );
+ fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) );
fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
dx = to_x - ras.x;
dy = to_y - ras.y;
- /* XXX: we should do something about the trivial case where dx == 0, */
- /* as it happens very often! */
-
/* perform vertical clipping */
- {
- TCoord min, max;
-
-
- min = ey1;
- max = ey2;
- if ( ey1 > ey2 )
- {
- min = ey2;
- max = ey1;
- }
- if ( min >= ras.max_ey || max < ras.min_ey )
- goto End;
- }
+ if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
+ ( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
+ goto End;
/* everything is on a single scanline */
if ( ey1 == ey2 )
@@ -771,13 +767,7 @@
if ( ey1 != ey2 )
{
p = ONE_PIXEL * dx;
- lift = (int)( p / dy );
- rem = (int)( p % dy );
- if ( rem < 0 )
- {
- lift--;
- rem += (int)dy;
- }
+ QT_FT_DIV_MOD( int, p, dy, lift, rem );
mod -= (int)dy;
while ( ey1 != ey2 )
@@ -808,10 +798,147 @@
End:
ras.x = to_x;
ras.y = to_y;
- ras.last_ey = SUBPIXELS( ey2 );
}
+#else
+
+ /*************************************************************************/
+ /* */
+ /* Render a straight line across multiple cells in any direction. */
+ /* */
+ static void
+ gray_render_line( RAS_ARG_ TPos to_x,
+ TPos to_y )
+ {
+ TPos dx, dy, fx1, fy1, fx2, fy2;
+ TCoord ex1, ex2, ey1, ey2;
+
+
+ ex1 = TRUNC( ras.x );
+ ex2 = TRUNC( to_x );
+ ey1 = TRUNC( ras.y );
+ ey2 = TRUNC( to_y );
+
+ /* perform vertical clipping */
+ if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) ||
+ ( ey1 < ras.min_ey && ey2 < ras.min_ey ) )
+ goto End;
+
+ dx = to_x - ras.x;
+ dy = to_y - ras.y;
+
+ fx1 = ras.x - SUBPIXELS( ex1 );
+ fy1 = ras.y - SUBPIXELS( ey1 );
+
+ if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */
+ ;
+ else if ( dy == 0 ) /* ex1 != ex2 */ /* any horizontal line */
+ {
+ ex1 = ex2;
+ gray_set_cell( RAS_VAR_ ex1, ey1 );
+ }
+ else if ( dx == 0 )
+ {
+ if ( dy > 0 ) /* vertical line up */
+ do
+ {
+ fy2 = ONE_PIXEL;
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * fx1 * 2;
+ fy1 = 0;
+ ey1++;
+ gray_set_cell( RAS_VAR_ ex1, ey1 );
+ } while ( ey1 != ey2 );
+ else /* vertical line down */
+ do
+ {
+ fy2 = 0;
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * fx1 * 2;
+ fy1 = ONE_PIXEL;
+ ey1--;
+ gray_set_cell( RAS_VAR_ ex1, ey1 );
+ } while ( ey1 != ey2 );
+ }
+ else /* any other line */
+ {
+ TArea prod = dx * fy1 - dy * fx1;
+ QT_FT_UDIVPREP( dx );
+ QT_FT_UDIVPREP( dy );
+
+
+ /* The fundamental value `prod' determines which side and the */
+ /* exact coordinate where the line exits current cell. It is */
+ /* also easily updated when moving from one cell to the next. */
+ do
+ {
+ if ( prod <= 0 &&
+ prod - dx * ONE_PIXEL > 0 ) /* left */
+ {
+ fx2 = 0;
+ fy2 = (TPos)QT_FT_UDIV( -prod, -dx );
+ prod -= dy * ONE_PIXEL;
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
+ fx1 = ONE_PIXEL;
+ fy1 = fy2;
+ ex1--;
+ }
+ else if ( prod - dx * ONE_PIXEL <= 0 &&
+ prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0 ) /* up */
+ {
+ prod -= dx * ONE_PIXEL;
+ fx2 = (TPos)QT_FT_UDIV( -prod, dy );
+ fy2 = ONE_PIXEL;
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
+ fx1 = fx2;
+ fy1 = 0;
+ ey1++;
+ }
+ else if ( prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
+ prod + dy * ONE_PIXEL >= 0 ) /* right */
+ {
+ prod += dy * ONE_PIXEL;
+ fx2 = ONE_PIXEL;
+ fy2 = (TPos)QT_FT_UDIV( prod, dx );
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
+ fx1 = 0;
+ fy1 = fy2;
+ ex1++;
+ }
+ else /* ( prod + dy * ONE_PIXEL < 0 &&
+ prod > 0 ) down */
+ {
+ fx2 = (TPos)QT_FT_UDIV( prod, -dy );
+ fy2 = 0;
+ prod += dx * ONE_PIXEL;
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
+ fx1 = fx2;
+ fy1 = ONE_PIXEL;
+ ey1--;
+ }
+
+ gray_set_cell( RAS_VAR_ ex1, ey1 );
+ } while ( ex1 != ex2 || ey1 != ey2 );
+ }
+
+ fx2 = to_x - SUBPIXELS( ex2 );
+ fy2 = to_y - SUBPIXELS( ey2 );
+
+ ras.cover += ( fy2 - fy1 );
+ ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 );
+
+ End:
+ ras.x = to_x;
+ ras.y = to_y;
+ }
+
+#endif
+
static void
gray_split_conic( QT_FT_Vector* base )
{
@@ -836,52 +963,11 @@
gray_render_conic( RAS_ARG_ const QT_FT_Vector* control,
const QT_FT_Vector* to )
{
+ QT_FT_Vector bez_stack[16 * 2 + 1]; /* enough to accommodate bisections */
+ QT_FT_Vector* arc = bez_stack;
TPos dx, dy;
- int top, level;
- int* levels;
- QT_FT_Vector* arc;
-
-
- dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
- if ( dx < 0 )
- dx = -dx;
- dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
- if ( dy < 0 )
- dy = -dy;
- if ( dx < dy )
- dx = dy;
-
- level = 1;
- dx = dx / ras.conic_level;
- while ( dx > 0 )
- {
- dx >>= 2;
- level++;
- }
+ int draw, split;
- /* a shortcut to speed things up */
- if ( level <= 1 )
- {
- /* we compute the mid-point directly in order to avoid */
- /* calling gray_split_conic() */
- TPos to_x, to_y, mid_x, mid_y;
-
-
- to_x = UPSCALE( to->x );
- to_y = UPSCALE( to->y );
- mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
- mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
-
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
-
- return;
- }
-
- arc = ras.bez_stack;
- levels = ras.lev_stack;
- top = 0;
- levels[0] = level;
arc[0].x = UPSCALE( to->x );
arc[0].y = UPSCALE( to->y );
@@ -890,54 +976,51 @@
arc[2].x = ras.x;
arc[2].y = ras.y;
- while ( top >= 0 )
+ /* short-cut the arc that crosses the current band */
+ if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
+ TRUNC( arc[1].y ) >= ras.max_ey &&
+ TRUNC( arc[2].y ) >= ras.max_ey ) ||
+ ( TRUNC( arc[0].y ) < ras.min_ey &&
+ TRUNC( arc[1].y ) < ras.min_ey &&
+ TRUNC( arc[2].y ) < ras.min_ey ) )
{
- level = levels[top];
- if ( level > 1 )
- {
- /* check that the arc crosses the current band */
- TPos min, max, y;
-
-
- min = max = arc[0].y;
-
- y = arc[1].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
+ ras.x = arc[0].x;
+ ras.y = arc[0].y;
+ return;
+ }
- y = arc[2].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
+ dx = QT_FT_ABS( arc[2].x + arc[0].x - 2 * arc[1].x );
+ dy = QT_FT_ABS( arc[2].y + arc[0].y - 2 * arc[1].y );
+ if ( dx < dy )
+ dx = dy;
- if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < ras.min_ey )
- goto Draw;
+ /* We can calculate the number of necessary bisections because */
+ /* each bisection predictably reduces deviation exactly 4-fold. */
+ /* Even 32-bit deviation would vanish after 16 bisections. */
+ draw = 1;
+ while ( dx > ONE_PIXEL / 4 )
+ {
+ dx >>= 2;
+ draw <<= 1;
+ }
+ /* We use decrement counter to count the total number of segments */
+ /* to draw starting from 2^level. Before each draw we split as */
+ /* many times as there are trailing zeros in the counter. */
+ do
+ {
+ split = 1;
+ while ( ( draw & split ) == 0 )
+ {
gray_split_conic( arc );
arc += 2;
- top++;
- levels[top] = levels[top - 1] = level - 1;
- continue;
+ split <<= 1;
}
- Draw:
- {
- TPos to_x, to_y, mid_x, mid_y;
-
-
- to_x = arc[0].x;
- to_y = arc[0].y;
- mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
- mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
-
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
-
- top--;
- arc -= 2;
- }
- }
+ gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
+ arc -= 2;
- return;
+ } while ( --draw );
}
@@ -974,60 +1057,13 @@
const QT_FT_Vector* control2,
const QT_FT_Vector* to )
{
- TPos dx, dy, da, db;
- int top, level;
- int* levels;
- QT_FT_Vector* arc;
+ QT_FT_Vector bez_stack[16 * 3 + 1]; /* enough to accommodate bisections */
+ QT_FT_Vector* arc = bez_stack;
+ TPos dx, dy, dx_, dy_;
+ TPos dx1, dy1, dx2, dy2;
+ TPos L, s, s_limit;
- dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
- if ( dx < 0 )
- dx = -dx;
- dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
- if ( dy < 0 )
- dy = -dy;
- if ( dx < dy )
- dx = dy;
- da = dx;
-
- dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
- if ( dx < 0 )
- dx = -dx;
- dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->y + control2->y );
- if ( dy < 0 )
- dy = -dy;
- if ( dx < dy )
- dx = dy;
- db = dx;
-
- level = 1;
- da = da / ras.cubic_level;
- db = db / ras.conic_level;
- while ( da > 0 || db > 0 )
- {
- da >>= 2;
- db >>= 3;
- level++;
- }
-
- if ( level <= 1 )
- {
- TPos to_x, to_y, mid_x, mid_y;
-
-
- to_x = UPSCALE( to->x );
- to_y = UPSCALE( to->y );
- mid_x = ( ras.x + to_x +
- 3 * UPSCALE( control1->x + control2->x ) ) / 8;
- mid_y = ( ras.y + to_y +
- 3 * UPSCALE( control1->y + control2->y ) ) / 8;
-
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
- return;
- }
-
- arc = ras.bez_stack;
arc[0].x = UPSCALE( to->x );
arc[0].y = UPSCALE( to->y );
arc[1].x = UPSCALE( control2->x );
@@ -1037,56 +1073,77 @@
arc[3].x = ras.x;
arc[3].y = ras.y;
- levels = ras.lev_stack;
- top = 0;
- levels[0] = level;
+ /* short-cut the arc that crosses the current band */
+ if ( ( TRUNC( arc[0].y ) >= ras.max_ey &&
+ TRUNC( arc[1].y ) >= ras.max_ey &&
+ TRUNC( arc[2].y ) >= ras.max_ey &&
+ TRUNC( arc[3].y ) >= ras.max_ey ) ||
+ ( TRUNC( arc[0].y ) < ras.min_ey &&
+ TRUNC( arc[1].y ) < ras.min_ey &&
+ TRUNC( arc[2].y ) < ras.min_ey &&
+ TRUNC( arc[3].y ) < ras.min_ey ) )
+ {
+ ras.x = arc[0].x;
+ ras.y = arc[0].y;
+ return;
+ }
- while ( top >= 0 )
+ for (;;)
{
- level = levels[top];
- if ( level > 1 )
- {
- /* check that the arc crosses the current band */
- TPos min, max, y;
-
-
- min = max = arc[0].y;
- y = arc[1].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
- y = arc[2].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
- y = arc[3].y;
- if ( y < min ) min = y;
- if ( y > max ) max = y;
- if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
- goto Draw;
- gray_split_cubic( arc );
- arc += 3;
- top ++;
- levels[top] = levels[top - 1] = level - 1;
- continue;
- }
+ /* Decide whether to split or draw. See `Rapid Termination */
+ /* Evaluation for Recursive Subdivision of Bezier Curves' by Thomas */
+ /* F. Hain, at */
+ /* http://www.cis.southalabama.edu/~hain/general/Publications/Bezier/Camera-ready%20CISST02%202.pdf */
- Draw:
- {
- TPos to_x, to_y, mid_x, mid_y;
+ /* dx and dy are x and y components of the P0-P3 chord vector. */
+ dx = dx_ = arc[3].x - arc[0].x;
+ dy = dy_ = arc[3].y - arc[0].y;
- to_x = arc[0].x;
- to_y = arc[0].y;
- mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
- mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
+ L = QT_FT_HYPOT( dx_, dy_ );
- gray_render_line( RAS_VAR_ mid_x, mid_y );
- gray_render_line( RAS_VAR_ to_x, to_y );
- top --;
- arc -= 3;
- }
- }
+ /* Avoid possible arithmetic overflow below by splitting. */
+ if ( L > 32767 )
+ goto Split;
+
+ /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */
+ s_limit = L * (TPos)( ONE_PIXEL / 6 );
+
+ /* s is L * the perpendicular distance from P1 to the line P0-P3. */
+ dx1 = arc[1].x - arc[0].x;
+ dy1 = arc[1].y - arc[0].y;
+ s = QT_FT_ABS( dy * dx1 - dx * dy1 );
+
+ if ( s > s_limit )
+ goto Split;
+
+ /* s is L * the perpendicular distance from P2 to the line P0-P3. */
+ dx2 = arc[2].x - arc[0].x;
+ dy2 = arc[2].y - arc[0].y;
+ s = QT_FT_ABS( dy * dx2 - dx * dy2 );
+
+ if ( s > s_limit )
+ goto Split;
+
+ /* Split super curvy segments where the off points are so far
+ from the chord that the angles P0-P1-P3 or P0-P2-P3 become
+ acute as detected by appropriate dot products. */
+ if ( dx1 * ( dx1 - dx ) + dy1 * ( dy1 - dy ) > 0 ||
+ dx2 * ( dx2 - dx ) + dy2 * ( dy2 - dy ) > 0 )
+ goto Split;
- return;
+ gray_render_line( RAS_VAR_ arc[0].x, arc[0].y );
+
+ if ( arc == bez_stack )
+ return;
+
+ arc -= 3;
+ continue;
+
+ Split:
+ gray_split_cubic( arc );
+ arc += 3;
+ }
}
@@ -1099,7 +1156,8 @@
/* record current cell, if any */
- gray_record_cell( worker );
+ if ( !ras.invalid )
+ gray_record_cell( worker );
/* start to a new position */
x = UPSCALE( to->x );
@@ -1107,15 +1165,15 @@
gray_start_cell( worker, TRUNC( x ), TRUNC( y ) );
- worker->x = x;
- worker->y = y;
+ ras.x = x;
+ ras.y = y;
return 0;
}
static void
- gray_render_span( int count,
+ gray_render_span( int count,
const QT_FT_Span* spans,
- PWorker worker )
+ PWorker worker )
{
unsigned char* p;
QT_FT_Bitmap* map = &worker->target;
@@ -1127,34 +1185,30 @@
/* first of all, compute the scanline offset */
p = (unsigned char*)map->buffer - spans->y * map->pitch;
if ( map->pitch >= 0 )
- p += ( map->rows - 1 ) * map->pitch;
+ p += ( map->rows - 1 ) * (unsigned int)map->pitch;
if ( coverage )
{
+ unsigned char* q = p + spans->x;
+
+
/* For small-spans it is faster to do it by ourselves than
* calling `memset'. This is mainly due to the cost of the
* function call.
*/
- if ( spans->len >= 8 )
- QT_FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
- else
+ switch ( spans->len )
{
- unsigned char* q = p + spans->x;
-
-
- switch ( spans->len )
- {
- case 7: *q++ = (unsigned char)coverage; Q_FALLTHROUGH();
- case 6: *q++ = (unsigned char)coverage; Q_FALLTHROUGH();
- case 5: *q++ = (unsigned char)coverage; Q_FALLTHROUGH();
- case 4: *q++ = (unsigned char)coverage; Q_FALLTHROUGH();
- case 3: *q++ = (unsigned char)coverage; Q_FALLTHROUGH();
- case 2: *q++ = (unsigned char)coverage; Q_FALLTHROUGH();
- case 1: *q = (unsigned char)coverage;
- default:
- ;
- }
+ case 7: *q++ = coverage; Q_FALLTHROUGH();
+ case 6: *q++ = coverage; Q_FALLTHROUGH();
+ case 5: *q++ = coverage; Q_FALLTHROUGH();
+ case 4: *q++ = coverage; Q_FALLTHROUGH();
+ case 3: *q++ = coverage; Q_FALLTHROUGH();
+ case 2: *q++ = coverage; Q_FALLTHROUGH();
+ case 1: *q = coverage; Q_FALLTHROUGH();
+ case 0: break;
+ default:
+ QT_FT_MEM_SET( q, coverage, spans->len );
}
}
}
@@ -1167,9 +1221,7 @@
TPos area,
int acount )
{
- QT_FT_Span* span;
- int coverage;
- int skip;
+ int coverage;
/* compute the coverage line's coverage, depending on the */
@@ -1202,14 +1254,24 @@
x += (TCoord)ras.min_ex;
/* QT_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */
- if ( x >= 32768 )
+ if ( x >= 32767 )
x = 32767;
+ /* QT_FT_Span.y is a 16-bit short, so limit our coordinates appropriately */
+ if ( y >= 32767 )
+ y = 32767;
+
if ( coverage )
{
+ QT_FT_Span* span;
+ int count;
+ int skip;
+
+
/* see whether we can add this span to the current list */
- span = ras.gray_spans + ras.num_gray_spans - 1;
- if ( ras.num_gray_spans > 0 &&
+ count = ras.num_gray_spans;
+ span = ras.gray_spans + count - 1;
+ if ( count > 0 &&
span->y == y &&
(int)span->x + span->len == (int)x &&
span->coverage == coverage )
@@ -1218,9 +1280,9 @@
return;
}
- if ( ras.num_gray_spans >= QT_FT_MAX_GRAY_SPANS )
+ if ( count >= QT_FT_MAX_GRAY_SPANS )
{
- if ( ras.render_span && ras.num_gray_spans > ras.skip_spans )
+ if ( ras.render_span && count > ras.skip_spans )
{
skip = ras.skip_spans > 0 ? ras.skip_spans : 0;
ras.render_span( ras.num_gray_spans - skip,
@@ -1302,6 +1364,8 @@
if ( ras.num_cells == 0 )
return;
+ QT_FT_TRACE7(( "gray_sweep: start\n" ));
+
for ( yindex = 0; yindex < ras.ycount; yindex++ )
{
PCell cell = ras.ycells[yindex];
@@ -1331,6 +1395,8 @@
gray_hline( RAS_VAR_ x, yindex, cover * ( ONE_PIXEL * 2 ),
ras.count_ex - x );
}
+
+ QT_FT_TRACE7(( "gray_sweep: end\n" ));
}
/*************************************************************************/
@@ -1364,7 +1430,7 @@
/* */
static
int QT_FT_Outline_Decompose( const QT_FT_Outline* outline,
- void* user )
+ void* user )
{
#undef SCALED
#define SCALED( x ) (x)
@@ -1382,6 +1448,9 @@
int error;
char tag; /* current point's state */
+ if ( !outline )
+ return ErrRaster_Invalid_Outline;
+
first = 0;
for ( n = 0; n < outline->n_contours; n++ )
@@ -1390,16 +1459,17 @@
last = outline->contours[n];
+ if ( last < 0 )
+ goto Invalid_Outline;
limit = outline->points + last;
- v_start = outline->points[first];
- v_last = outline->points[last];
-
+ v_start = outline->points[first];
v_start.x = SCALED( v_start.x );
v_start.y = SCALED( v_start.y );
- v_last.x = SCALED( v_last.x );
- v_last.y = SCALED( v_last.y );
+ v_last = outline->points[last];
+ v_last.x = SCALED( v_last.x );
+ v_last.y = SCALED( v_last.y );
v_control = v_start;
@@ -1435,6 +1505,8 @@
tags--;
}
+ QT_FT_TRACE5(( " move to (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0 ));
error = gray_move_to( &v_start, user );
if ( error )
goto Exit;
@@ -1455,6 +1527,8 @@
vec.x = SCALED( point->x );
vec.y = SCALED( point->y );
+ QT_FT_TRACE5(( " line to (%.2f, %.2f)\n",
+ vec.x / 64.0, vec.y / 64.0 ));
gray_render_line(user, UPSCALE(vec.x), UPSCALE(vec.y));
continue;
}
@@ -1480,6 +1554,10 @@
if ( tag == QT_FT_CURVE_TAG_ON )
{
+ QT_FT_TRACE5(( " conic to (%.2f, %.2f)"
+ " with control (%.2f, %.2f)\n",
+ vec.x / 64.0, vec.y / 64.0,
+ v_control.x / 64.0, v_control.y / 64.0 ));
gray_render_conic(user, &v_control, &vec);
continue;
}
@@ -1490,11 +1568,20 @@
v_middle.x = ( v_control.x + vec.x ) / 2;
v_middle.y = ( v_control.y + vec.y ) / 2;
+ QT_FT_TRACE5(( " conic to (%.2f, %.2f)"
+ " with control (%.2f, %.2f)\n",
+ v_middle.x / 64.0, v_middle.y / 64.0,
+ v_control.x / 64.0, v_control.y / 64.0 ));
gray_render_conic(user, &v_control, &v_middle);
+
v_control = vec;
goto Do_Conic;
}
+ QT_FT_TRACE5(( " conic to (%.2f, %.2f)"
+ " with control (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0,
+ v_control.x / 64.0, v_control.y / 64.0 ));
gray_render_conic(user, &v_control, &v_start);
goto Close;
}
@@ -1525,10 +1612,20 @@
vec.x = SCALED( point->x );
vec.y = SCALED( point->y );
+ QT_FT_TRACE5(( " cubic to (%.2f, %.2f)"
+ " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
+ vec.x / 64.0, vec.y / 64.0,
+ vec1.x / 64.0, vec1.y / 64.0,
+ vec2.x / 64.0, vec2.y / 64.0 ));
gray_render_cubic(user, &vec1, &vec2, &vec);
continue;
}
+ QT_FT_TRACE5(( " cubic to (%.2f, %.2f)"
+ " with controls (%.2f, %.2f) and (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0,
+ vec1.x / 64.0, vec1.y / 64.0,
+ vec2.x / 64.0, vec2.y / 64.0 ));
gray_render_cubic(user, &vec1, &vec2, &v_start);
goto Close;
}
@@ -1536,15 +1633,19 @@
}
/* close the contour with a line segment */
+ QT_FT_TRACE5(( " line to (%.2f, %.2f)\n",
+ v_start.x / 64.0, v_start.y / 64.0 ));
gray_render_line(user, UPSCALE(v_start.x), UPSCALE(v_start.y));
Close:
first = last + 1;
}
+ QT_FT_TRACE5(( "FT_Outline_Decompose: Done\n", n ));
return 0;
Exit:
+ QT_FT_TRACE5(( "FT_Outline_Decompose: Error %d\n", error ));
return error;
Invalid_Outline:
@@ -1557,7 +1658,6 @@
} TBand;
-
static int
gray_convert_glyph_inner( RAS_ARG )
{
@@ -1566,7 +1666,8 @@
if ( qt_ft_setjmp( ras.jump_buffer ) == 0 )
{
error = QT_FT_Outline_Decompose( &ras.outline, &ras );
- gray_record_cell( RAS_VAR );
+ if ( !ras.invalid )
+ gray_record_cell( RAS_VAR );
}
else
{
@@ -1608,29 +1709,12 @@
ras.count_ex = ras.max_ex - ras.min_ex;
ras.count_ey = ras.max_ey - ras.min_ey;
- /* simple heuristic used to speed-up the bezier decomposition -- see */
- /* the code in gray_render_conic() and gray_render_cubic() for more */
- /* details */
- ras.conic_level = 32;
- ras.cubic_level = 16;
-
- {
- int level = 0;
-
-
- if ( ras.count_ex > 24 || ras.count_ey > 24 )
- level++;
- if ( ras.count_ex > 120 || ras.count_ey > 120 )
- level++;
-
- ras.conic_level <<= level;
- ras.cubic_level <<= level;
- }
-
- /* setup vertical bands */
+ /* set up vertical bands */
num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
- if ( num_bands == 0 ) num_bands = 1;
- if ( num_bands >= 39 ) num_bands = 39;
+ if ( num_bands == 0 )
+ num_bands = 1;
+ if ( num_bands >= 39 )
+ num_bands = 39;
ras.band_shoot = 0;
@@ -1764,11 +1848,14 @@
if (raster->buffer_allocated_size < MINIMUM_POOL_SIZE )
return ErrRaster_OutOfMemory;
+ if ( !outline )
+ return ErrRaster_Invalid_Outline;
+
/* return immediately if the outline is empty */
if ( outline->n_points == 0 || outline->n_contours <= 0 )
return 0;
- if ( !outline || !outline->contours || !outline->points )
+ if ( !outline->contours || !outline->points )
return ErrRaster_Invalid_Outline;
if ( outline->n_points !=
diff --git a/src/gui/painting/qpagedpaintdevice.cpp b/src/gui/painting/qpagedpaintdevice.cpp
index 22ec981134..1c7d6471b6 100644
--- a/src/gui/painting/qpagedpaintdevice.cpp
+++ b/src/gui/painting/qpagedpaintdevice.cpp
@@ -243,6 +243,18 @@ QPagedPaintDevicePrivate *QPagedPaintDevice::dd()
Starts a new page. Returns \c true on success.
*/
+/*!
+ \enum QPagedPaintDevice::PdfVersion
+
+ The PdfVersion enum describes the version of the PDF file that
+ is produced by QPrinter or QPdfWriter.
+
+ \value PdfVersion_1_4 A PDF 1.4 compatible document is produced.
+
+ \value PdfVersion_A1b A PDF/A-1b compatible document is produced.
+
+ \since 5.10
+*/
/*!
Sets the size of the a page to \a size.
diff --git a/src/gui/painting/qpagedpaintdevice.h b/src/gui/painting/qpagedpaintdevice.h
index c516f6a963..66dd6fa8cf 100644
--- a/src/gui/painting/qpagedpaintdevice.h
+++ b/src/gui/painting/qpagedpaintdevice.h
@@ -213,6 +213,8 @@ public:
Envelope10 = Comm10E
};
+ enum PdfVersion { PdfVersion_1_4, PdfVersion_A1b };
+
// ### Qt6 Make these virtual
bool setPageLayout(const QPageLayout &pageLayout);
bool setPageSize(const QPageSize &pageSize);
diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp
index ddea168e72..1aee7d5f74 100644
--- a/src/gui/painting/qpaintengine.cpp
+++ b/src/gui/painting/qpaintengine.cpp
@@ -547,8 +547,8 @@ void qt_fill_tile(QPixmap *tile, const QPixmap &pixmap)
}
}
-void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h,
- const QPixmap &pixmap, qreal xOffset, qreal yOffset)
+Q_GUI_EXPORT void qt_draw_tile(QPaintEngine *gc, qreal x, qreal y, qreal w, qreal h,
+ const QPixmap &pixmap, qreal xOffset, qreal yOffset)
{
qreal yPos, xPos, drawH, drawW, yOff, xOff;
yPos = y;
@@ -751,11 +751,29 @@ void QPaintEngine::drawPath(const QPainterPath &)
void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
{
const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
+ if (ti.glyphs.numGlyphs == 0)
+ return;
+
+ if (ti.fontEngine->glyphFormat == QFontEngine::Format_ARGB) {
+ QVarLengthArray<QFixedPoint> positions;
+ QVarLengthArray<glyph_t> glyphs;
+ QTransform matrix = QTransform::fromTranslate(p.x(), p.y() - ti.fontEngine->ascent().toReal());
+ ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+ painter()->save();
+ painter()->setRenderHint(QPainter::SmoothPixmapTransform,
+ bool((painter()->renderHints() & QPainter::TextAntialiasing)
+ && !(painter()->font().styleStrategy() & QFont::NoAntialias)));
+ for (int i = 0; i < ti.glyphs.numGlyphs; ++i) {
+ QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixed(), QTransform());
+ painter()->drawImage(positions[i].x.toReal(), positions[i].y.toReal(), glyph);
+ }
+ painter()->restore();
+ return;
+ }
QPainterPath path;
path.setFillRule(Qt::WindingFill);
- if (ti.glyphs.numGlyphs)
- ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, ti.flags);
+ ti.fontEngine->addOutlineToPath(0, 0, ti.glyphs, &path, ti.flags);
if (!path.isEmpty()) {
painter()->save();
painter()->setRenderHint(QPainter::Antialiasing,
@@ -929,11 +947,11 @@ QPoint QPaintEngine::coordinateOffset() const
void QPaintEngine::setSystemClip(const QRegion &region)
{
Q_D(QPaintEngine);
- d->systemClip = region;
+ d->baseSystemClip = region;
// Be backward compatible and only call d->systemStateChanged()
// if we currently have a system transform/viewport set.
+ d->updateSystemClip();
if (d->hasSystemTransform || d->hasSystemViewport) {
- d->transformSystemClip();
d->systemStateChanged();
}
}
diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h
index 9d511f9bad..8ac3fcff5c 100644
--- a/src/gui/painting/qpaintengine_p.h
+++ b/src/gui/painting/qpaintengine_p.h
@@ -71,6 +71,7 @@ public:
QPaintDevice *pdev;
QPaintEngine *q_ptr;
+ QRegion baseSystemClip;
QRegion systemClip;
QRect systemRect;
QRegion systemViewport;
@@ -79,8 +80,9 @@ public:
uint hasSystemTransform : 1;
uint hasSystemViewport : 1;
- inline void transformSystemClip()
+ inline void updateSystemClip()
{
+ systemClip = baseSystemClip;
if (systemClip.isEmpty())
return;
@@ -104,15 +106,30 @@ public:
inline void setSystemTransform(const QTransform &xform)
{
systemTransform = xform;
- if ((hasSystemTransform = !xform.isIdentity()) || hasSystemViewport)
- transformSystemClip();
- systemStateChanged();
+ hasSystemTransform = !xform.isIdentity();
+ updateSystemClip();
+ if (q_ptr->state)
+ systemStateChanged();
}
inline void setSystemViewport(const QRegion &region)
{
systemViewport = region;
hasSystemViewport = !systemViewport.isEmpty();
+ updateSystemClip();
+ if (q_ptr->state)
+ systemStateChanged();
+ }
+
+ inline void setSystemTransformAndViewport(const QTransform &xform, const QRegion &region)
+ {
+ systemTransform = xform;
+ hasSystemTransform = !xform.isIdentity();
+ systemViewport = region;
+ hasSystemViewport = !systemViewport.isEmpty();
+ updateSystemClip();
+ if (q_ptr->state)
+ systemStateChanged();
}
virtual void systemStateChanged() { }
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 92ab6e8375..1637a933b1 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -50,6 +50,7 @@
#include <qdebug.h>
#include <qbitmap.h>
#include <qmath.h>
+#include <qrandom.h>
// #include <private/qdatabuffer_p.h>
// #include <private/qpainter_p.h>
@@ -993,7 +994,7 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
Q_ASSERT(img.depth() >= 8);
- int srcBPL = img.bytesPerLine();
+ qsizetype srcBPL = img.bytesPerLine();
const uchar *srcBits = img.bits();
int srcSize = img.depth() >> 3; // This is the part that is incompatible with lower than 8-bit..
int iw = img.width();
@@ -1042,7 +1043,7 @@ void QRasterPaintEnginePrivate::drawImage(const QPointF &pt,
// call the blend function...
int dstSize = rasterBuffer->bytesPerPixel();
- int dstBPL = rasterBuffer->bytesPerLine();
+ qsizetype dstBPL = rasterBuffer->bytesPerLine();
func(rasterBuffer->buffer() + x * dstSize + y * dstBPL, dstBPL,
srcBits, srcBPL,
iw, ih,
@@ -2317,8 +2318,8 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
clippedSourceRect = clippedSourceRect.intersected(img.rect());
- uint dbpl = d->rasterBuffer->bytesPerLine();
- uint sbpl = img.bytesPerLine();
+ const qsizetype dbpl = d->rasterBuffer->bytesPerLine();
+ const qsizetype sbpl = img.bytesPerLine();
uchar *dst = d->rasterBuffer->buffer();
uint bpp = img.depth() >> 3;
@@ -2827,7 +2828,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
cache->fillInPendingGlyphs();
const QImage &image = cache->image();
- int bpl = image.bytesPerLine();
+ qsizetype bpl = image.bytesPerLine();
int depth = image.depth();
int rightShift = 0;
@@ -4229,7 +4230,7 @@ protected:
QSharedPointer<const CacheInfo> addCacheElement(quint64 hash_val, const QGradient &gradient, int opacity) {
if (cache.size() == maxCacheSize()) {
// may remove more than 1, but OK
- cache.erase(cache.begin() + (qrand() % maxCacheSize()));
+ cache.erase(cache.begin() + QRandomGenerator::global()->bounded(maxCacheSize()));
}
auto cache_entry = QSharedPointer<CacheInfo>::create(gradient.stops(), opacity, gradient.interpolationMode());
generateGradientColorTable(gradient, cache_entry->buffer64, paletteSize(), opacity);
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index d0b82b3a93..e2e0f821e3 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -457,6 +457,8 @@ public:
int height() const { return m_height; }
int bytesPerLine() const { return bytes_per_line; }
int bytesPerPixel() const { return bytes_per_pixel; }
+ template<typename T>
+ int stride() { return bytes_per_line / sizeof(T); }
uchar *buffer() const { return m_buffer; }
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 49d8fd2846..6e84a3f384 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -5850,6 +5850,7 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif
if (!d->engine || str.isEmpty() || pen().style() == Qt::NoPen)
return;
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (tf & Qt::TextBypassShaping) {
// Skip complex shaping, shape using glyph advances only
int len = str.length();
@@ -5863,6 +5864,7 @@ void QPainter::drawText(const QPointF &p, const QString &str, int tf, int justif
drawTextItem(p, gf);
return;
}
+#endif
QStackTextEngine engine(str, d->state->font);
engine.option.setTextDirection(d->state->layoutDirection);
@@ -6480,7 +6482,7 @@ void QPainterPrivate::drawTextItem(const QPointF &p, const QTextItem &_ti, QText
extended->drawTextItem(QPointF(x, y), ti2);
else
engine->drawTextItem(QPointF(x, y), ti2);
- drawTextItemDecoration(q, p, ti2.fontEngine, textEngine, ti2.underlineStyle,
+ drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
ti2.flags, ti2.width.toReal(), ti2.charFormat);
if (!rtl)
@@ -6513,7 +6515,7 @@ void QPainterPrivate::drawTextItem(const QPointF &p, const QTextItem &_ti, QText
extended->drawTextItem(QPointF(x, y), ti2);
else
engine->drawTextItem(QPointF(x,y), ti2);
- drawTextItemDecoration(q, p, ti2.fontEngine, textEngine, ti2.underlineStyle,
+ drawTextItemDecoration(q, QPointF(x, y), ti2.fontEngine, textEngine, ti2.underlineStyle,
ti2.flags, ti2.width.toReal(), ti2.charFormat);
// reset the high byte for all glyphs
@@ -7419,7 +7421,7 @@ void qt_format_text(const QFont &fnt, const QRectF &_r,
if (option->flags() & QTextOption::IncludeTrailingSpaces)
tf |= Qt::TextIncludeTrailingSpaces;
- if (option->tabStop() >= 0 || !option->tabArray().isEmpty())
+ if (option->tabStopDistance() >= 0 || !option->tabArray().isEmpty())
tf |= Qt::TextExpandTabs;
}
@@ -7536,8 +7538,8 @@ start_lengthVariant:
engine.option = *option;
}
- if (engine.option.tabStop() < 0 && tabstops > 0)
- engine.option.setTabStop(tabstops);
+ if (engine.option.tabStopDistance() < 0 && tabstops > 0)
+ engine.option.setTabStopDistance(tabstops);
if (engine.option.tabs().isEmpty() && ta) {
QList<qreal> tabs;
diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp
index afeb198953..e421055ef3 100644
--- a/src/gui/painting/qpdf.cpp
+++ b/src/gui/painting/qpdf.cpp
@@ -42,16 +42,20 @@
#ifndef QT_NO_PDF
#include "qplatformdefs.h"
-#include <qdebug.h>
-#include <qfile.h>
-#include <qtemporaryfile.h>
+
+#include <private/qfont_p.h>
#include <private/qmath_p.h>
#include <private/qpainter_p.h>
-#include <qnumeric.h>
-#include "private/qfont_p.h"
+
+#include <qbuffer.h>
+#include <qcryptographichash.h>
+#include <qdatetime.h>
+#include <qdebug.h>
+#include <qfile.h>
#include <qimagewriter.h>
-#include "qbuffer.h"
-#include "QtCore/qdatetime.h"
+#include <qnumeric.h>
+#include <qtemporaryfile.h>
+#include <quuid.h>
#ifndef QT_NO_COMPRESS
#include <zlib.h>
@@ -79,6 +83,45 @@ inline QPaintEngine::PaintEngineFeatures qt_pdf_decide_features()
return f;
}
+extern bool qt_isExtendedRadialGradient(const QBrush &brush);
+
+// helper function to remove transparency from brush in PDF/A-1b mode
+static void removeTransparencyFromBrush(QBrush &brush)
+{
+ if (brush.style() == Qt::SolidPattern) {
+ QColor color = brush.color();
+ if (color.alpha() != 255) {
+ color.setAlpha(255);
+ brush.setColor(color);
+ }
+
+ return;
+ }
+
+ if (qt_isExtendedRadialGradient(brush)) {
+ brush = QBrush(Qt::black); // the safest we can do so far...
+ return;
+ }
+
+ if (brush.style() == Qt::LinearGradientPattern
+ || brush.style() == Qt::RadialGradientPattern
+ || brush.style() == Qt::ConicalGradientPattern) {
+
+ QGradientStops stops = brush.gradient()->stops();
+ for (int i = 0; i < stops.size(); ++i) {
+ if (stops[i].second.alpha() != 255)
+ stops[i].second.setAlpha(255);
+ }
+
+ const_cast<QGradient*>(brush.gradient())->setStops(stops);
+ return;
+ }
+
+ if (brush.style() == Qt::TexturePattern) {
+ // handled inside QPdfEnginePrivate::addImage() already
+ return;
+ }
+}
/* also adds a space at the end of the number */
@@ -1020,7 +1063,12 @@ void QPdfEngine::drawHyperlink(const QRectF &r, const QUrl &url)
char buf[256];
const QRectF rr = d->pageMatrix().mapRect(r);
- d->xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [");
+ d->xprintf("<<\n/Type /Annot\n/Subtype /Link\n");
+
+ if (d->pdfVersion == QPdfEngine::Version_A1b)
+ d->xprintf("/F 4\n"); // enable print flag, disable all other
+
+ d->xprintf("/Rect [");
d->xprintf("%s ", qt_real_to_string(rr.left(), buf));
d->xprintf("%s ", qt_real_to_string(rr.top(), buf));
d->xprintf("%s ", qt_real_to_string(rr.right(), buf));
@@ -1042,7 +1090,22 @@ void QPdfEngine::updateState(const QPaintEngineState &state)
d->stroker.matrix = state.transform();
if (flags & DirtyPen) {
- d->pen = state.pen();
+ if (d->pdfVersion == QPdfEngine::Version_A1b) {
+ QPen pen = state.pen();
+
+ QColor penColor = pen.color();
+ if (penColor.alpha() != 255)
+ penColor.setAlpha(255);
+ pen.setColor(penColor);
+
+ QBrush penBrush = pen.brush();
+ removeTransparencyFromBrush(penBrush);
+ pen.setBrush(penBrush);
+
+ d->pen = pen;
+ } else {
+ d->pen = state.pen();
+ }
d->hasPen = d->pen.style() != Qt::NoPen;
d->stroker.setPen(d->pen, state.renderHints());
QBrush penBrush = d->pen.brush();
@@ -1054,7 +1117,13 @@ void QPdfEngine::updateState(const QPaintEngineState &state)
d->stroker.setPen(d->pen, state.renderHints());
}
if (flags & DirtyBrush) {
- d->brush = state.brush();
+ if (d->pdfVersion == QPdfEngine::Version_A1b) {
+ QBrush brush = state.brush();
+ removeTransparencyFromBrush(brush);
+ d->brush = brush;
+ } else {
+ d->brush = state.brush();
+ }
if (d->brush.color().alpha() == 0 && d->brush.style() == Qt::SolidPattern)
d->brush.setStyle(Qt::NoBrush);
d->hasBrush = d->brush.style() != Qt::NoBrush;
@@ -1286,6 +1355,12 @@ int QPdfEngine::resolution() const
return d->resolution;
}
+void QPdfEngine::setPdfVersion(PdfVersion version)
+{
+ Q_D(QPdfEngine);
+ d->pdfVersion = version;
+}
+
void QPdfEngine::setPageLayout(const QPageLayout &pageLayout)
{
Q_D(QPdfEngine);
@@ -1364,6 +1439,7 @@ int QPdfEngine::metric(QPaintDevice::PaintDeviceMetric metricType) const
QPdfEnginePrivate::QPdfEnginePrivate()
: clipEnabled(false), allClipped(false), hasPen(true), hasBrush(false), simplePen(false),
+ pdfVersion(QPdfEngine::Version_1_4),
outDevice(0), ownsDevice(false),
embedFonts(true),
grayscale(false),
@@ -1465,16 +1541,38 @@ void QPdfEnginePrivate::writeHeader()
addXrefEntry(0,false);
xprintf("%%PDF-1.4\n");
+ xprintf("%%\303\242\303\243\n");
writeInfo();
+ int metaDataObj = -1;
+ int outputIntentObj = -1;
+ if (pdfVersion == QPdfEngine::Version_A1b) {
+ metaDataObj = writeXmpMetaData();
+ outputIntentObj = writeOutputIntent();
+ }
+
catalog = addXrefEntry(-1);
pageRoot = requestObject();
- xprintf("<<\n"
- "/Type /Catalog\n"
- "/Pages %d 0 R\n"
- ">>\n"
- "endobj\n", pageRoot);
+
+ // catalog
+ {
+ QByteArray catalog;
+ QPdf::ByteStream s(&catalog);
+ s << "<<\n"
+ << "/Type /Catalog\n"
+ << "/Pages " << pageRoot << "0 R\n";
+
+ if (pdfVersion == QPdfEngine::Version_A1b) {
+ s << "/OutputIntents [" << outputIntentObj << "0 R]\n";
+ s << "/Metadata " << metaDataObj << "0 R\n";
+ }
+
+ s << ">>\n"
+ << "endobj\n";
+
+ write(catalog);
+ }
// graphics state
graphicsState = addXrefEntry(-1);
@@ -1527,6 +1625,95 @@ void QPdfEnginePrivate::writeInfo()
"endobj\n");
}
+int QPdfEnginePrivate::writeXmpMetaData()
+{
+ const int metaDataObj = addXrefEntry(-1);
+
+ const QString producer(QString::fromLatin1("Qt " QT_VERSION_STR));
+
+ const QDateTime now = QDateTime::currentDateTime();
+ const QDate date = now.date();
+ const QTime time = now.time();
+
+ QString timeStr;
+ timeStr.sprintf("%d-%02d-%02dT%02d:%02d:%02d", date.year(), date.month(), date.day(),
+ time.hour(), time.minute(), time.second());
+
+ const int offset = now.offsetFromUtc();
+ const int hours = (offset / 60) / 60;
+ const int mins = (offset / 60) % 60;
+ QString tzStr;
+ if (offset < 0)
+ tzStr.sprintf("-%02d:%02d", -hours, -mins);
+ else if (offset > 0)
+ tzStr.sprintf("+%02d:%02d", hours , mins);
+ else
+ tzStr = QLatin1String("Z");
+
+ const QString metaDataDate = timeStr + tzStr;
+
+ QFile metaDataFile(QLatin1String(":/qpdf/qpdfa_metadata.xml"));
+ metaDataFile.open(QIODevice::ReadOnly);
+ const QByteArray metaDataContent = QString::fromUtf8(metaDataFile.readAll()).arg(producer.toHtmlEscaped(),
+ title.toHtmlEscaped(),
+ creator.toHtmlEscaped(),
+ metaDataDate).toUtf8();
+ xprintf("<<\n"
+ "/Type /Metadata /Subtype /XML\n"
+ "/Length %d\n"
+ ">>\n"
+ "stream\n", metaDataContent.size());
+ write(metaDataContent);
+ xprintf("\nendstream\n"
+ "endobj\n");
+
+ return metaDataObj;
+}
+
+int QPdfEnginePrivate::writeOutputIntent()
+{
+ const int colorProfile = addXrefEntry(-1);
+ {
+ QFile colorProfileFile(QLatin1String(":/qpdf/sRGB2014.icc"));
+ colorProfileFile.open(QIODevice::ReadOnly);
+ const QByteArray colorProfileData = colorProfileFile.readAll();
+
+ QByteArray data;
+ QPdf::ByteStream s(&data);
+ int length_object = requestObject();
+
+ s << "<<\n";
+ s << "/N 3\n";
+ s << "/Alternate /DeviceRGB\n";
+ s << "/Length " << length_object << "0 R\n";
+ s << "/Filter /FlateDecode\n";
+ s << ">>\n";
+ s << "stream\n";
+ write(data);
+ const int len = writeCompressed(colorProfileData);
+ write("\nendstream\n"
+ "endobj\n");
+ addXrefEntry(length_object);
+ xprintf("%d\n"
+ "endobj\n", len);
+ }
+
+ const int outputIntent = addXrefEntry(-1);
+ {
+ xprintf("<<\n");
+ xprintf("/Type /OutputIntent\n");
+ xprintf("/S/GTS_PDFA1\n");
+ xprintf("/OutputConditionIdentifier (sRGB_IEC61966-2-1_black_scaled)\n");
+ xprintf("/DestOutputProfile %d 0 R\n", colorProfile);
+ xprintf("/Info(sRGB IEC61966 v2.1 with black scaling)\n");
+ xprintf("/RegistryName(http://www.color.org)\n");
+ xprintf(">>\n");
+ xprintf("endobj\n");
+ }
+
+ return outputIntent;
+}
+
void QPdfEnginePrivate::writePageRoot()
{
addXrefEntry(pageRoot);
@@ -1568,6 +1755,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
int fontstream = requestObject();
int cidfont = requestObject();
int toUnicode = requestObject();
+ int cidset = requestObject();
QFontEngine::Properties properties = font->fontEngine->properties();
QByteArray postscriptName = properties.postscriptName.replace(' ', '_');
@@ -1597,7 +1785,8 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
"/CapHeight " << properties.capHeight.toReal()*scale << "\n"
"/StemV " << properties.lineWidth.toReal()*scale << "\n"
"/FontFile2 " << fontstream << "0 R\n"
- ">> endobj\n";
+ "/CIDSet " << cidset << "0 R\n"
+ ">>\nendobj\n";
write(descriptor);
}
{
@@ -1615,7 +1804,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
"stream\n";
write(header);
int len = writeCompressed(fontData);
- write("endstream\n"
+ write("\nendstream\n"
"endobj\n");
addXrefEntry(length_object);
xprintf("%d\n"
@@ -1642,7 +1831,7 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
xprintf("<< /Length %d >>\n"
"stream\n", touc.length());
write(touc);
- write("endstream\n"
+ write("\nendstream\n"
"endobj\n");
}
{
@@ -1659,6 +1848,29 @@ void QPdfEnginePrivate::embedFont(QFontSubset *font)
"endobj\n";
write(font);
}
+ {
+ QByteArray cidSetStream(font->nGlyphs() / 8 + 1, 0);
+ int byteCounter = 0;
+ int bitCounter = 0;
+ for (int i = 0; i < font->nGlyphs(); ++i) {
+ cidSetStream.data()[byteCounter] |= (1 << (7 - bitCounter));
+
+ bitCounter++;
+ if (bitCounter == 8) {
+ bitCounter = 0;
+ byteCounter++;
+ }
+ }
+
+ addXrefEntry(cidset);
+ xprintf("<<\n");
+ xprintf("/Length %d\n", cidSetStream.size());
+ xprintf(">>\n");
+ xprintf("stream\n");
+ write(cidSetStream);
+ xprintf("\nendstream\n");
+ xprintf("endobj\n");
+ }
}
@@ -1748,7 +1960,7 @@ void QPdfEnginePrivate::writePage()
xprintf("stream\n");
QIODevice *content = currentPage->stream();
int len = writeCompressed(content);
- xprintf("endstream\n"
+ xprintf("\nendstream\n"
"endobj\n");
addXrefEntry(pageStreamLength);
@@ -1768,15 +1980,28 @@ void QPdfEnginePrivate::writeTail()
for (int i = 1; i < xrefPositions.size()-1; ++i)
xprintf("%010d 00000 n \n", xrefPositions[i]);
- xprintf("trailer\n"
- "<<\n"
- "/Size %d\n"
- "/Info %d 0 R\n"
- "/Root %d 0 R\n"
- ">>\n"
- "startxref\n%d\n"
- "%%%%EOF\n",
- xrefPositions.size()-1, info, catalog, xrefPositions.constLast());
+ {
+ QByteArray trailer;
+ QPdf::ByteStream s(&trailer);
+
+ s << "trailer\n"
+ << "<<\n"
+ << "/Size " << xrefPositions.size() - 1 << "\n"
+ << "/Info " << info << "0 R\n"
+ << "/Root " << catalog << "0 R\n";
+
+ if (pdfVersion == QPdfEngine::Version_A1b) {
+ const QString uniqueId = QUuid::createUuid().toString();
+ const QByteArray fileIdentifier = QCryptographicHash::hash(uniqueId.toLatin1(), QCryptographicHash::Md5).toHex();
+ s << "/ID [ <" << fileIdentifier << "> <" << fileIdentifier << "> ]\n";
+ }
+
+ s << ">>\n"
+ << "startxref\n" << xrefPositions.constLast() << "\n"
+ << "%%EOF\n";
+
+ write(trailer);
+ }
}
int QPdfEnginePrivate::addXrefEntry(int object, bool printostr)
@@ -1794,7 +2019,13 @@ int QPdfEnginePrivate::addXrefEntry(int object, bool printostr)
return object;
}
-void QPdfEnginePrivate::printString(const QString &string) {
+void QPdfEnginePrivate::printString(const QString &string)
+{
+ if (string.isEmpty()) {
+ write("()");
+ return;
+ }
+
// The 'text string' type in PDF is encoded either as PDFDocEncoding, or
// Unicode UTF-16 with a Unicode byte order mark as the first character
// (0xfeff), with the high-order byte first.
@@ -1976,7 +2207,7 @@ int QPdfEnginePrivate::writeImage(const QByteArray &data, int width, int height,
xprintf(">>\nstream\n");
len = writeCompressed(data);
}
- xprintf("endstream\n"
+ xprintf("\nendstream\n"
"endobj\n");
addXrefEntry(lenobj);
xprintf("%d\n"
@@ -2303,7 +2534,7 @@ int QPdfEnginePrivate::gradientBrush(const QBrush &b, const QTransform &matrix,
">>\n"
"stream\n"
<< content
- << "endstream\n"
+ << "\nendstream\n"
"endobj\n";
int softMaskFormObject = addXrefEntry(-1);
@@ -2412,7 +2643,7 @@ int QPdfEnginePrivate::addBrushPattern(const QTransform &m, bool *specifyColor,
">>\n"
"stream\n"
<< pattern
- << "endstream\n"
+ << "\nendstream\n"
"endobj\n";
int patternObj = addXrefEntry(-1);
@@ -2443,6 +2674,23 @@ int QPdfEnginePrivate::addImage(const QImage &img, bool *bitmap, qint64 serial_n
QImage image = img;
QImage::Format format = image.format();
+
+ if (pdfVersion == QPdfEngine::Version_A1b) {
+ if (image.hasAlphaChannel()) {
+ // transparent images are not allowed in PDF/A-1b, so we convert it to
+ // a format without alpha channel first
+
+ QImage alphaLessImage(image.width(), image.height(), QImage::Format_RGB32);
+ alphaLessImage.fill(Qt::white);
+
+ QPainter p(&alphaLessImage);
+ p.drawImage(0, 0, image);
+
+ image = alphaLessImage;
+ format = image.format();
+ }
+ }
+
if (image.depth() == 1 && *bitmap && is_monochrome(img.colorTable())) {
if (format == QImage::Format_MonoLSB)
image = image.convertToFormat(QImage::Format_Mono);
@@ -2588,7 +2836,12 @@ void QPdfEnginePrivate::drawTextItem(const QPointF &p, const QTextItemInt &ti)
x2s.setNum(static_cast<double>(x2), 'f');
y2s.setNum(static_cast<double>(y2), 'f');
QByteArray rectData = x1s + ' ' + y1s + ' ' + x2s + ' ' + y2s;
- xprintf("<<\n/Type /Annot\n/Subtype /Link\n/Rect [");
+ xprintf("<<\n/Type /Annot\n/Subtype /Link\n");
+
+ if (pdfVersion == QPdfEngine::Version_A1b)
+ xprintf("/F 4\n"); // enable print flag, disable all other
+
+ xprintf("/Rect [");
xprintf(rectData.constData());
#ifdef Q_DEBUG_PDF_LINKS
xprintf("]\n/Border [16 16 1]\n/A <<\n");
diff --git a/src/gui/painting/qpdf.qrc b/src/gui/painting/qpdf.qrc
new file mode 100644
index 0000000000..56359c775b
--- /dev/null
+++ b/src/gui/painting/qpdf.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+ <qresource prefix="qpdf/">
+ <file>qpdfa_metadata.xml</file>
+ <file alias="sRGB2014.icc">../../3rdparty/icc/sRGB2014.icc</file>
+ </qresource>
+</RCC>
diff --git a/src/gui/painting/qpdf_p.h b/src/gui/painting/qpdf_p.h
index a6aa2940c8..f5bb4e17a8 100644
--- a/src/gui/painting/qpdf_p.h
+++ b/src/gui/painting/qpdf_p.h
@@ -168,6 +168,12 @@ class Q_GUI_EXPORT QPdfEngine : public QPaintEngine
Q_DECLARE_PRIVATE(QPdfEngine)
friend class QPdfWriter;
public:
+ enum PdfVersion
+ {
+ Version_1_4,
+ Version_A1b
+ };
+
QPdfEngine();
QPdfEngine(QPdfEnginePrivate &d);
~QPdfEngine() {}
@@ -177,6 +183,8 @@ public:
void setResolution(int resolution);
int resolution() const;
+ void setPdfVersion(PdfVersion version);
+
// reimplementations QPaintEngine
bool begin(QPaintDevice *pdev) Q_DECL_OVERRIDE;
bool end() Q_DECL_OVERRIDE;
@@ -258,6 +266,7 @@ public:
bool hasBrush;
bool simplePen;
qreal opacity;
+ QPdfEngine::PdfVersion pdfVersion;
QHash<QFontEngine::FaceId, QFontSubset *> fonts;
@@ -286,6 +295,8 @@ private:
int createShadingFunction(const QGradient *gradient, int from, int to, bool reflect, bool alpha);
void writeInfo();
+ int writeXmpMetaData();
+ int writeOutputIntent();
void writePageRoot();
void writeFonts();
void embedFont(QFontSubset *font);
diff --git a/src/gui/painting/qpdfa_metadata.xml b/src/gui/painting/qpdfa_metadata.xml
new file mode 100644
index 0000000000..5e5c57f1c6
--- /dev/null
+++ b/src/gui/painting/qpdfa_metadata.xml
@@ -0,0 +1,16 @@
+<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description xmlns:dc="http://purl.org/dc/elements/1.1/" rdf:about="">
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">%2</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ </rdf:Description>
+ <rdf:Description xmlns:xmp="http://ns.adobe.com/xap/1.0/" rdf:about="" xmp:CreatorTool="%3" xmp:CreateDate="%4" xmp:ModifyDate="%4"/>
+ <rdf:Description xmlns:pdf="http://ns.adobe.com/pdf/1.3/" rdf:about="" pdf:Producer="%1"/>
+ <rdf:Description xmlns:pdfaid="http://www.aiim.org/pdfa/ns/id/" rdf:about="" pdfaid:part="1" pdfaid:conformance="B"/>
+ </rdf:RDF>
+</x:xmpmeta>
+<?xpacket end='w'?>
diff --git a/src/gui/painting/qpdfwriter.cpp b/src/gui/painting/qpdfwriter.cpp
index edf2950a67..5af465edeb 100644
--- a/src/gui/painting/qpdfwriter.cpp
+++ b/src/gui/painting/qpdfwriter.cpp
@@ -56,6 +56,7 @@ public:
{
engine = new QPdfEngine();
output = 0;
+ pdfVersion = QPdfWriter::PdfVersion_1_4;
}
~QPdfWriterPrivate()
{
@@ -65,6 +66,7 @@ public:
QPdfEngine *engine;
QFile *output;
+ QPdfWriter::PdfVersion pdfVersion;
};
class QPdfPagedPaintDevicePrivate : public QPagedPaintDevicePrivate
@@ -177,6 +179,35 @@ QPdfWriter::~QPdfWriter()
}
/*!
+ \since 5.10
+
+ Sets the PDF version for this writer to \a version.
+
+ If \a version is the same value as currently set then no change will be made.
+*/
+void QPdfWriter::setPdfVersion(PdfVersion version)
+{
+ Q_D(QPdfWriter);
+
+ if (d->pdfVersion == version)
+ return;
+
+ d->pdfVersion = version;
+ d->engine->setPdfVersion(d->pdfVersion == QPdfWriter::PdfVersion_1_4 ? QPdfEngine::Version_1_4 : QPdfEngine::Version_A1b);
+}
+
+/*!
+ \since 5.10
+
+ Returns the PDF version for this writer. The default is \c PdfVersion_1_4.
+*/
+QPdfWriter::PdfVersion QPdfWriter::pdfVersion() const
+{
+ Q_D(const QPdfWriter);
+ return d->pdfVersion;
+}
+
+/*!
Returns the title of the document.
*/
QString QPdfWriter::title() const
diff --git a/src/gui/painting/qpdfwriter.h b/src/gui/painting/qpdfwriter.h
index 17c73dd480..b260805b2b 100644
--- a/src/gui/painting/qpdfwriter.h
+++ b/src/gui/painting/qpdfwriter.h
@@ -61,6 +61,9 @@ public:
explicit QPdfWriter(QIODevice *device);
~QPdfWriter();
+ void setPdfVersion(PdfVersion version);
+ PdfVersion pdfVersion() const;
+
QString title() const;
void setTitle(const QString &title);
diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp
index 8215255cf5..8ab22beb31 100644
--- a/src/gui/painting/qplatformbackingstore.cpp
+++ b/src/gui/painting/qplatformbackingstore.cpp
@@ -50,6 +50,7 @@
#include <QtGui/QOpenGLFunctions>
#ifndef QT_NO_OPENGL
#include <QtGui/qopengltextureblitter.h>
+#include <QtGui/qoffscreensurface.h>
#endif
#include <qpa/qplatformgraphicsbuffer.h>
#include <qpa/qplatformgraphicsbufferhelper.h>
@@ -70,6 +71,13 @@
#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
#endif
+#ifndef GL_FRAMEBUFFER_SRB
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#endif
+#ifndef GL_FRAMEBUFFER_SRGB_CAPABLE
+#define GL_FRAMEBUFFER_SRGB_CAPABLE 0x8DBA
+#endif
+
QT_BEGIN_NAMESPACE
class QPlatformBackingStorePrivate
@@ -88,14 +96,15 @@ public:
~QPlatformBackingStorePrivate()
{
#ifndef QT_NO_OPENGL
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- if (ctx) {
+ if (context) {
+ QOffscreenSurface offscreenSurface;
+ offscreenSurface.setFormat(context->format());
+ offscreenSurface.create();
+ context->makeCurrent(&offscreenSurface);
if (textureId)
- ctx->functions()->glDeleteTextures(1, &textureId);
+ context->functions()->glDeleteTextures(1, &textureId);
if (blitter)
blitter->destroy();
- } else if (textureId || blitter) {
- qWarning("No context current during QPlatformBackingStore destruction, OpenGL resources not released");
}
delete blitter;
#endif
@@ -103,6 +112,7 @@ public:
QWindow *window;
QBackingStore *backingStore;
#ifndef QT_NO_OPENGL
+ QScopedPointer<QOpenGLContext> context;
mutable GLuint textureId;
mutable QSize textureSize;
mutable bool needsSwizzle;
@@ -227,17 +237,6 @@ void QPlatformTextureList::clear()
windows.
*/
-/*!
- \fn void QPlatformBackingStore::flush(QWindow *window, const QRegion &region,
- const QPoint &offset)
-
- Flushes the given \a region from the specified \a window onto the
- screen.
-
- The \a offset parameter is relative to the origin of the backing
- store image.
-*/
-
#ifndef QT_NO_OPENGL
static inline QRect deviceRect(const QRect &rect, QWindow *window)
@@ -274,7 +273,7 @@ static inline QRect toBottomLeftRect(const QRect &topLeftRect, int windowHeight)
}
static void blitTextureForWidget(const QPlatformTextureList *textures, int idx, QWindow *window, const QRect &deviceWindowRect,
- QOpenGLTextureBlitter *blitter, const QPoint &offset)
+ QOpenGLTextureBlitter *blitter, const QPoint &offset, bool canUseSrgb)
{
const QRect clipRect = textures->clipRect(idx);
if (clipRect.isEmpty())
@@ -294,7 +293,15 @@ static void blitTextureForWidget(const QPlatformTextureList *textures, int idx,
deviceRect(rectInWindow, window).size(),
QOpenGLTextureBlitter::OriginBottomLeft);
+ QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
+ const bool srgb = textures->flags(idx).testFlag(QPlatformTextureList::TextureIsSrgb);
+ if (srgb && canUseSrgb)
+ funcs->glEnable(GL_FRAMEBUFFER_SRGB);
+
blitter->blit(textures->textureId(idx), target, source);
+
+ if (srgb && canUseSrgb)
+ funcs->glDisable(GL_FRAMEBUFFER_SRGB);
}
/*!
@@ -312,20 +319,31 @@ static void blitTextureForWidget(const QPlatformTextureList *textures, int idx,
void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &region,
const QPoint &offset,
- QPlatformTextureList *textures, QOpenGLContext *context,
+ QPlatformTextureList *textures,
bool translucentBackground)
{
if (!qt_window_private(window)->receivedExpose)
return;
- if (!context->makeCurrent(window)) {
+ if (!d_ptr->context) {
+ d_ptr->context.reset(new QOpenGLContext);
+ d_ptr->context->setFormat(d_ptr->window->requestedFormat());
+ d_ptr->context->setScreen(d_ptr->window->screen());
+ d_ptr->context->setShareContext(qt_window_private(d_ptr->window)->shareContext());
+ if (!d_ptr->context->create()) {
+ qWarning("composeAndFlush: QOpenGLContext creation failed");
+ return;
+ }
+ }
+
+ if (!d_ptr->context->makeCurrent(window)) {
qWarning("composeAndFlush: makeCurrent() failed");
return;
}
QWindowPrivate::get(window)->lastComposeTime.start();
- QOpenGLFunctions *funcs = context->functions();
+ QOpenGLFunctions *funcs = d_ptr->context->functions();
funcs->glViewport(0, 0, window->width() * window->devicePixelRatio(), window->height() * window->devicePixelRatio());
funcs->glClearColor(0, 0, 0, translucentBackground ? 0 : 1);
funcs->glClear(GL_COLOR_BUFFER_BIT);
@@ -340,10 +358,23 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
const QRect deviceWindowRect = deviceRect(QRect(QPoint(), window->size()), window);
const QPoint deviceWindowOffset = deviceOffset(offset, window);
+ bool canUseSrgb = false;
+ // If there are any sRGB textures in the list, check if the destination
+ // framebuffer is sRGB capable.
+ for (int i = 0; i < textures->count(); ++i) {
+ if (textures->flags(i).testFlag(QPlatformTextureList::TextureIsSrgb)) {
+ GLint cap = 0;
+ funcs->glGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE, &cap);
+ if (cap)
+ canUseSrgb = true;
+ break;
+ }
+ }
+
// Textures for renderToTexture widgets.
for (int i = 0; i < textures->count(); ++i) {
if (!textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
- blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset);
+ blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
}
// Backingstore texture with the normal widgets.
@@ -412,13 +443,13 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
// Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set.
for (int i = 0; i < textures->count(); ++i) {
if (textures->flags(i).testFlag(QPlatformTextureList::StacksOnTop))
- blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset);
+ blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset, canUseSrgb);
}
funcs->glDisable(GL_BLEND);
d_ptr->blitter->release();
- context->swapBuffers(window);
+ d_ptr->context->swapBuffers(window);
}
#endif
/*!
diff --git a/src/gui/painting/qplatformbackingstore.h b/src/gui/painting/qplatformbackingstore.h
index ec56aaa002..381c564079 100644
--- a/src/gui/painting/qplatformbackingstore.h
+++ b/src/gui/painting/qplatformbackingstore.h
@@ -78,7 +78,8 @@ class Q_GUI_EXPORT QPlatformTextureList : public QObject
Q_DECLARE_PRIVATE(QPlatformTextureList)
public:
enum Flag {
- StacksOnTop = 0x01
+ StacksOnTop = 0x01,
+ TextureIsSrgb = 0x02
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -116,12 +117,10 @@ public:
virtual QPaintDevice *paintDevice() = 0;
- // 'window' can be a child window, in which case 'region' is in child window coordinates and
- // offset is the (child) window's offset in relation to the window surface.
virtual void flush(QWindow *window, const QRegion &region, const QPoint &offset) = 0;
#ifndef QT_NO_OPENGL
virtual void composeAndFlush(QWindow *window, const QRegion &region, const QPoint &offset,
- QPlatformTextureList *textures, QOpenGLContext *context,
+ QPlatformTextureList *textures,
bool translucentBackground);
#endif
virtual QImage toImage() const;
diff --git a/src/gui/painting/qpolygon.cpp b/src/gui/painting/qpolygon.cpp
index 126b752811..3bf6004fcc 100644
--- a/src/gui/painting/qpolygon.cpp
+++ b/src/gui/painting/qpolygon.cpp
@@ -909,6 +909,8 @@ QPolygon QPolygon::united(const QPolygon &r) const
Set operations on polygons will treat the polygons as
areas. Non-closed polygons will be treated as implicitly closed.
+
+ \sa intersects()
*/
QPolygon QPolygon::intersected(const QPolygon &r) const
@@ -938,6 +940,26 @@ QPolygon QPolygon::subtracted(const QPolygon &r) const
}
/*!
+ \since 5.10
+
+ Returns \c true if the current polygon intersects at any point the given polygon \a p.
+ Also returns \c true if the current polygon contains or is contained by any part of \a p.
+
+ Set operations on polygons will treat the polygons as
+ areas. Non-closed polygons will be treated as implicitly closed.
+
+ \sa intersected()
+*/
+
+bool QPolygon::intersects(const QPolygon &p) const
+{
+ QPainterPath subject; subject.addPolygon(*this);
+ QPainterPath clip; clip.addPolygon(p);
+
+ return subject.intersects(clip);
+}
+
+/*!
\since 4.3
Returns a polygon which is the union of this polygon and \a r.
@@ -964,6 +986,7 @@ QPolygonF QPolygonF::united(const QPolygonF &r) const
Set operations on polygons will treat the polygons as
areas. Non-closed polygons will be treated as implicitly closed.
+ \sa intersects()
*/
QPolygonF QPolygonF::intersected(const QPolygonF &r) const
@@ -992,6 +1015,26 @@ QPolygonF QPolygonF::subtracted(const QPolygonF &r) const
}
/*!
+ \since 5.10
+
+ Returns \c true if the current polygon intersects at any point the given polygon \a p.
+ Also returns \c true if the current polygon contains or is contained by any part of \a p.
+
+ Set operations on polygons will treat the polygons as
+ areas. Non-closed polygons will be treated as implicitly closed.
+
+ \sa intersected()
+*/
+
+bool QPolygonF::intersects(const QPolygonF &p) const
+{
+ QPainterPath subject; subject.addPolygon(*this);
+ QPainterPath clip; clip.addPolygon(p);
+
+ return subject.intersects(clip);
+}
+
+/*!
Returns the polygon as a QVariant.
*/
diff --git a/src/gui/painting/qpolygon.h b/src/gui/painting/qpolygon.h
index f192e8d10b..8e74a499fd 100644
--- a/src/gui/painting/qpolygon.h
+++ b/src/gui/painting/qpolygon.h
@@ -98,6 +98,8 @@ public:
Q_REQUIRED_RESULT QPolygon united(const QPolygon &r) const;
Q_REQUIRED_RESULT QPolygon intersected(const QPolygon &r) const;
Q_REQUIRED_RESULT QPolygon subtracted(const QPolygon &r) const;
+
+ bool intersects(const QPolygon &r) const;
};
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QPolygon)
@@ -175,6 +177,8 @@ public:
Q_REQUIRED_RESULT QPolygonF united(const QPolygonF &r) const;
Q_REQUIRED_RESULT QPolygonF intersected(const QPolygonF &r) const;
Q_REQUIRED_RESULT QPolygonF subtracted(const QPolygonF &r) const;
+
+ bool intersects(const QPolygonF &r) const;
};
Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QPolygonF)
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp
index 4b5d4a48b6..e7ca00b3a9 100644
--- a/src/gui/text/qdistancefield.cpp
+++ b/src/gui/text/qdistancefield.cpp
@@ -436,7 +436,7 @@ static void drawPolygons(qint32 *bits, int width, int height, const QPoint *vert
const quint32 *indices, int indexCount, qint32 value)
{
Q_ASSERT(indexCount != 0);
- typedef QVarLengthArray<quint8, 16> ScanLine;
+ typedef QVarLengthArray<quint16, 16> ScanLine;
QVarLengthArray<ScanLine, 128> scans(height);
int first = 0;
for (int i = 1; i < indexCount; ++i) {
@@ -461,16 +461,16 @@ static void drawPolygons(qint32 *bits, int width, int height, const QPoint *vert
for (int y = fromY; y < toY; ++y) {
quint32 c = quint32(x >> 8);
if (c < quint32(width))
- scans[y].append(quint8(c));
+ scans[y].append(quint16(c));
x += dx;
}
}
for (int i = 0; i < height; ++i) {
- quint8 *scanline = scans[i].data();
+ quint16 *scanline = scans[i].data();
int size = scans[i].size();
for (int j = 1; j < size; ++j) {
int k = j;
- quint8 value = scanline[k];
+ quint16 value = scanline[k];
for (; k != 0 && value < scanline[k - 1]; --k)
scanline[k] = scanline[k - 1];
scanline[k] = value;
@@ -478,7 +478,7 @@ static void drawPolygons(qint32 *bits, int width, int height, const QPoint *vert
qint32 *line = bits + i * width;
int j = 0;
for (; j + 1 < size; j += 2) {
- for (quint8 x = scanline[j]; x < scanline[j + 1]; ++x)
+ for (quint16 x = scanline[j]; x < scanline[j + 1]; ++x)
line[x] = value;
}
if (j < size) {
@@ -516,7 +516,7 @@ static void makeDistanceField(QDistanceFieldData *data, const QPainterPath &path
for (int i = 0; i < imgWidth * imgHeight; ++i)
bits[i] = exteriorColor;
- const qreal angleStep = qreal(15 * 3.141592653589793238 / 180);
+ const qreal angleStep = qDegreesToRadians(qreal(15));
const QPoint rotation(qRound(qCos(angleStep) * 0x4000),
qRound(qSin(angleStep) * 0x4000)); // 2:14 signed
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 806ede88e2..438cd3de3a 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -1324,6 +1324,11 @@ QFont::StyleHint QFont::styleHint() const
looking font that contains the character. The NoFontMerging flag disables this feature.
Please note that enabling this flag will not prevent Qt from automatically picking a
suitable font when the selected font does not support the writing system of the text.
+ \value PreferNoShaping Sometimes, a font will apply complex rules to a set of characters in
+ order to display them correctly. In some writing systems, such as Brahmic scripts, this is
+ required in order for the text to be legible, but in e.g. Latin script, it is merely
+ a cosmetic feature. The PreferNoShaping flag will disable all such features when they
+ are not required, which will improve performance in most cases.
Any of these may be OR-ed with one of these flags:
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index 6f0dd27fbe..9c250c82c3 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -68,6 +68,7 @@ public:
Monospace,
Fantasy
};
+ Q_ENUM(StyleHint)
enum StyleStrategy {
PreferDefault = 0x0001,
@@ -82,6 +83,7 @@ public:
OpenGLCompatible = 0x0200,
ForceIntegerMetrics = 0x0400,
NoSubpixelAntialias = 0x0800,
+ PreferNoShaping = 0x1000,
NoFontMerging = 0x8000
};
Q_ENUM(StyleStrategy)
@@ -92,6 +94,7 @@ public:
PreferVerticalHinting = 2,
PreferFullHinting = 3
};
+ Q_ENUM(HintingPreference)
// Mapping OpenType weight value.
enum Weight {
@@ -105,12 +108,14 @@ public:
ExtraBold = 81, // 800
Black = 87 // 900
};
+ Q_ENUM(Weight)
enum Style {
StyleNormal,
StyleItalic,
StyleOblique
};
+ Q_ENUM(Style)
enum Stretch {
AnyStretch = 0,
@@ -124,6 +129,7 @@ public:
ExtraExpanded = 150,
UltraExpanded = 200
};
+ Q_ENUM(Stretch)
enum Capitalization {
MixedCase,
@@ -132,11 +138,13 @@ public:
SmallCaps,
Capitalize
};
+ Q_ENUM(Capitalization)
enum SpacingType {
PercentageSpacing,
AbsoluteSpacing
};
+ Q_ENUM(SpacingType)
enum ResolveProperties {
FamilyResolved = 0x0001,
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 29c48da7be..33df020a6c 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -359,10 +359,8 @@ bool QFontEngine::supportsScript(QChar::Script script) const
// ### TODO: This only works for scripts that require OpenType. More generally
// for scripts that do not require OpenType we should just look at the list of
// supported writing systems in the font's OS/2 table.
- if (!((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
- || script == QChar::Script_Khmer || script == QChar::Script_Nko)) {
+ if (!scriptRequiresOpenType(script))
return true;
- }
#if QT_CONFIG(harfbuzz)
if (qt_useHarfbuzzNG()) {
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 514e9424b2..1ae2e86a93 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -242,6 +242,12 @@ public:
void *harfbuzzFace() const;
bool supportsScript(QChar::Script script) const;
+ inline static bool scriptRequiresOpenType(QChar::Script script)
+ {
+ return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
+ || script == QChar::Script_Khmer || script == QChar::Script_Nko);
+ }
+
virtual int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints);
void clearGlyphCache(const void *key);
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 8067969f56..5675d6921d 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -541,6 +541,7 @@ int QFontMetrics::width(const QString &text, int len, int flags) const
if (len == 0)
return 0;
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (flags & Qt::TextBypassShaping) {
// Skip complex shaping, only use advances
int numGlyphs = len;
@@ -554,6 +555,7 @@ int QFontMetrics::width(const QString &text, int len, int flags) const
width += glyphs.advances[i];
return qRound(width);
}
+#endif
QStackTextEngine layout(text, QFont(d.data()));
return qRound(layout.width(0, len));
diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp
index 92eeaf7919..f5fc562e13 100644
--- a/src/gui/text/qfontsubset.cpp
+++ b/src/gui/text/qfontsubset.cpp
@@ -136,7 +136,7 @@ QByteArray QFontSubset::widthArray() const
QByteArray width;
QPdf::ByteStream s(&width);
- QFixed scale = QFixed(1000)/emSquare;
+ const qreal scale = 1000.0/emSquare.toInt();
QFixed defWidth = widths[0];
//qDebug("defWidth=%d, scale=%f", defWidth.toInt(), scale.toReal());
@@ -145,7 +145,7 @@ QByteArray QFontSubset::widthArray() const
defWidth = 0;
}
if (defWidth > 0) {
- s << "/DW " << (defWidth*scale).toInt();
+ s << "/DW " << qRound(defWidth.toInt() * scale);
} else {
s << "/W [";
for (int g = 0; g < nGlyphs();) {
@@ -174,11 +174,11 @@ QByteArray QFontSubset::widthArray() const
if (endnonlinear > start) {
s << start << '[';
for (int i = start; i < endnonlinear; ++i)
- s << (widths[i]*scale).toInt();
+ s << qRound(widths[i].toInt() * scale);
s << "]\n";
}
if (startLinear)
- s << startLinear << g - 1 << (widths[startLinear]*scale).toInt() << '\n';
+ s << startLinear << g - 1 << qRound(widths[startLinear].toInt() * scale) << '\n';
}
s << "]\n";
}
diff --git a/src/gui/text/qstatictext.h b/src/gui/text/qstatictext.h
index 00dfccc144..e6a196d865 100644
--- a/src/gui/text/qstatictext.h
+++ b/src/gui/text/qstatictext.h
@@ -62,7 +62,7 @@ public:
};
QStaticText();
- QStaticText(const QString &text);
+ explicit QStaticText(const QString &text);
QStaticText(const QStaticText &other);
#ifdef Q_COMPILER_RVALUE_REFS
QStaticText &operator=(QStaticText &&other) Q_DECL_NOTHROW { swap(other); return *this; }
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index f8215f92e9..db0650d154 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -71,7 +71,7 @@
QT_BEGIN_NAMESPACE
-Q_CORE_EXPORT unsigned int qt_int_sqrt(unsigned int n);
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n);
/*!
Returns \c true if the string \a text is likely to be rich text;
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index 7341fa8e83..66e038122c 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -203,7 +203,7 @@ QTextDocumentPrivate::QTextDocumentPrivate()
inContentsChange = false;
blockCursorAdjustment = false;
- defaultTextOption.setTabStop(80); // same as in qtextengine.cpp
+ defaultTextOption.setTabStopDistance(80); // same as in qtextengine.cpp
defaultTextOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
defaultCursorMoveStyle = Qt::LogicalMoveStyle;
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 4d24fb50af..faddb3552d 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1005,20 +1005,53 @@ void QTextEngine::shapeText(int item) const
QFontEngine *fontEngine = this->fontEngine(si, &si.ascent, &si.descent, &si.leading);
+ bool kerningEnabled;
+ bool letterSpacingIsAbsolute;
+ bool shapingEnabled;
+ QFixed letterSpacing, wordSpacing;
+#ifndef QT_NO_RAWFONT
+ if (useRawFont) {
+ QTextCharFormat f = format(&si);
+ kerningEnabled = f.fontKerning();
+ shapingEnabled = QFontEngine::scriptRequiresOpenType(QChar::Script(si.analysis.script))
+ || (f.fontStyleStrategy() & QFont::PreferNoShaping) == 0;
+ wordSpacing = QFixed::fromReal(f.fontWordSpacing());
+ letterSpacing = QFixed::fromReal(f.fontLetterSpacing());
+ letterSpacingIsAbsolute = true;
+ } else
+#endif
+ {
+ QFont font = this->font(si);
+ kerningEnabled = font.d->kerning;
+ shapingEnabled = QFontEngine::scriptRequiresOpenType(QChar::Script(si.analysis.script))
+ || (font.d->request.styleStrategy & QFont::PreferNoShaping) == 0;
+ letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute;
+ letterSpacing = font.d->letterSpacing;
+ wordSpacing = font.d->wordSpacing;
+
+ if (letterSpacingIsAbsolute && letterSpacing.value())
+ letterSpacing *= font.d->dpi / qt_defaultDpiY();
+ }
+
// split up the item into parts that come from different font engines
// k * 3 entries, array[k] == index in string, array[k + 1] == index in glyphs, array[k + 2] == engine index
QVector<uint> itemBoundaries;
itemBoundaries.reserve(24);
- if (fontEngine->type() == QFontEngine::Multi) {
+
+ QGlyphLayout initialGlyphs = availableGlyphs(&si);
+ int nGlyphs = initialGlyphs.numGlyphs;
+ if (fontEngine->type() == QFontEngine::Multi || !shapingEnabled) {
// ask the font engine to find out which glyphs (as an index in the specific font)
// to use for the text in one item.
- QGlyphLayout initialGlyphs = availableGlyphs(&si);
-
- int nGlyphs = initialGlyphs.numGlyphs;
- QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);
+ QFontEngine::ShaperFlags shaperFlags =
+ shapingEnabled
+ ? QFontEngine::GlyphIndicesOnly
+ : QFontEngine::ShaperFlag(0);
if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags))
Q_UNREACHABLE();
+ }
+ if (fontEngine->type() == QFontEngine::Multi) {
uint lastEngine = ~0u;
for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) {
const uint engineIdx = initialGlyphs.glyphs[glyph_pos] >> 24;
@@ -1046,35 +1079,29 @@ void QTextEngine::shapeText(int item) const
itemBoundaries.append(0);
}
- bool kerningEnabled;
- bool letterSpacingIsAbsolute;
- QFixed letterSpacing, wordSpacing;
-#ifndef QT_NO_RAWFONT
- if (useRawFont) {
- QTextCharFormat f = format(&si);
- kerningEnabled = f.fontKerning();
- wordSpacing = QFixed::fromReal(f.fontWordSpacing());
- letterSpacing = QFixed::fromReal(f.fontLetterSpacing());
- letterSpacingIsAbsolute = true;
- } else
-#endif
- {
- QFont font = this->font(si);
- kerningEnabled = font.d->kerning;
- letterSpacingIsAbsolute = font.d->letterSpacingIsAbsolute;
- letterSpacing = font.d->letterSpacing;
- wordSpacing = font.d->wordSpacing;
+ if (Q_UNLIKELY(!shapingEnabled)) {
+ ushort *log_clusters = logClusters(&si);
- if (letterSpacingIsAbsolute && letterSpacing.value())
- letterSpacing *= font.d->dpi / qt_defaultDpiY();
- }
+ int glyph_pos = 0;
+ for (int i = 0; i < itemLength; ++i, ++glyph_pos) {
+ log_clusters[i] = glyph_pos;
+ initialGlyphs.attributes[glyph_pos].clusterStart = true;
+ if (QChar::isHighSurrogate(string[i])
+ && i + 1 < itemLength
+ && QChar::isLowSurrogate(string[i + 1])) {
+ ++i;
+ log_clusters[i] = glyph_pos;
+ }
+ }
+ si.num_glyphs = glyph_pos;
#if QT_CONFIG(harfbuzz)
- if (Q_LIKELY(qt_useHarfbuzzNG()))
+ } else if (Q_LIKELY(qt_useHarfbuzzNG())) {
si.num_glyphs = shapeTextWithHarfbuzzNG(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled, letterSpacing != 0);
- else
#endif
- si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);
+ } else {
+ si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);
+ }
if (Q_UNLIKELY(si.num_glyphs == 0)) {
Q_UNREACHABLE(); // ### report shaping errors somehow
return;
@@ -3016,7 +3043,7 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
}
}
}
- QFixed tab = QFixed::fromReal(option.tabStop());
+ QFixed tab = QFixed::fromReal(option.tabStopDistance());
if (tab <= 0)
tab = 80; // default
tab *= dpiScale;
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index f49e2638f5..89f1328241 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -323,13 +323,9 @@ public:
QFontEngine *fontEngine;
};
-struct Q_AUTOTEST_EXPORT QScriptItem
+struct QScriptItem
{
- inline QScriptItem()
- : position(0),
- num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
- glyph_data_offset(0) {}
- inline QScriptItem(int p, const QScriptAnalysis &a)
+ Q_DECL_CONSTEXPR QScriptItem(int p, QScriptAnalysis a) Q_DECL_NOTHROW
: position(p), analysis(a),
num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
glyph_data_offset(0) {}
@@ -342,11 +338,12 @@ struct Q_AUTOTEST_EXPORT QScriptItem
QFixed leading;
QFixed width;
int glyph_data_offset;
- QFixed height() const { return ascent + descent; }
+ Q_DECL_CONSTEXPR QFixed height() const Q_DECL_NOTHROW { return ascent + descent; }
+private:
+ friend class QVector<QScriptItem>;
+ QScriptItem() {}; // for QVector, don't use
};
-
-
-Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QScriptItem, Q_PRIMITIVE_TYPE);
typedef QVector<QScriptItem> QScriptItemArray;
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 36e0a77bd0..8fe474af2c 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -164,24 +164,25 @@ QDataStream &operator>>(QDataStream &stream, QTextLength &length)
}
#endif // QT_NO_DATASTREAM
-class QTextFormatPrivate : public QSharedData
+namespace {
+struct Property
{
-public:
- QTextFormatPrivate() : hashDirty(true), fontDirty(true), hashValue(0) {}
+ inline Property(qint32 k, const QVariant &v) : key(k), value(v) {}
+ inline Property() {}
- struct Property
- {
- inline Property(qint32 k, const QVariant &v) : key(k), value(v) {}
- inline Property() {}
+ qint32 key = -1;
+ QVariant value;
- qint32 key;
- QVariant value;
+ inline bool operator==(const Property &other) const
+ { return key == other.key && value == other.value; }
+};
+}
+Q_DECLARE_TYPEINFO(Property, Q_MOVABLE_TYPE);
- inline bool operator==(const Property &other) const
- { return key == other.key && value == other.value; }
- inline bool operator!=(const Property &other) const
- { return key != other.key || value != other.value; }
- };
+class QTextFormatPrivate : public QSharedData
+{
+public:
+ QTextFormatPrivate() : hashDirty(true), fontDirty(true), hashValue(0) {}
inline uint hash() const
{
@@ -263,7 +264,6 @@ private:
friend QDataStream &operator<<(QDataStream &, const QTextFormat &);
friend QDataStream &operator>>(QDataStream &, QTextFormat &);
};
-Q_DECLARE_TYPEINFO(QTextFormatPrivate::Property, Q_MOVABLE_TYPE);
static inline uint hash(const QColor &color)
{
@@ -845,10 +845,10 @@ void QTextFormat::merge(const QTextFormat &other)
QTextFormatPrivate *d = this->d;
- const QVector<QTextFormatPrivate::Property> &otherProps = other.d->props;
+ const QVector<QT_PREPEND_NAMESPACE(Property)> &otherProps = other.d->props;
d->props.reserve(d->props.size() + otherProps.size());
for (int i = 0; i < otherProps.count(); ++i) {
- const QTextFormatPrivate::Property &p = otherProps.at(i);
+ const QT_PREPEND_NAMESPACE(Property) &p = otherProps.at(i);
d->insertProperty(p.key, p.value);
}
}
@@ -1333,9 +1333,9 @@ bool QTextFormat::operator==(const QTextFormat &rhs) const
\value DashDotLine Dashs and dots are drawn using Qt::DashDotLine.
\value DashDotDotLine Underlines draw drawn using Qt::DashDotDotLine.
\value WaveUnderline The text is underlined using a wave shaped line.
- \value SpellCheckUnderline The underline is drawn depending on the QStyle::SH_SpellCeckUnderlineStyle
- style hint of the QApplication style. By default this is mapped to
- WaveUnderline, on \macos it is mapped to DashDotLine.
+ \value SpellCheckUnderline The underline is drawn depending on the SpellCheckUnderlineStyle
+ theme hint of QPlatformTheme. By default this is mapped to
+ WaveUnderline, on \macos it is mapped to DotLine.
\sa Qt::PenStyle
*/
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index da4e21728f..be10efad8d 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -493,7 +493,7 @@ static QString quoteNewline(const QString &s)
QTextHtmlParserNode::QTextHtmlParserNode()
: parent(0), id(Html_unknown),
- cssFloat(QTextFrameFormat::InFlow), hasOwnListStyle(false), hasOwnLineHeightType(false),
+ cssFloat(QTextFrameFormat::InFlow), hasOwnListStyle(false), hasOwnLineHeightType(false), hasLineHeightMultiplier(false),
hasCssListIndent(false), isEmptyParagraph(false), isTextFrame(false), isRootFrame(false),
displayMode(QTextHtmlElement::DisplayInline), hasHref(false),
listStyle(QTextListFormat::ListStyleUndefined), imageWidth(-1), imageHeight(-1), tableBorder(0),
@@ -1216,6 +1216,11 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
else
lineHeightType = QTextBlockFormat::SingleHeight;
+ if (hasLineHeightMultiplier) {
+ qreal lineHeight = blockFormat.lineHeight() / 100.0;
+ blockFormat.setProperty(QTextBlockFormat::LineHeight, lineHeight);
+ }
+
blockFormat.setProperty(QTextBlockFormat::LineHeightType, lineHeightType);
hasOwnLineHeightType = true;
}
@@ -1227,9 +1232,14 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
lineHeightType = QTextBlockFormat::MinimumHeight;
} else {
bool ok;
- QString value = decl.d->values.first().toString();
+ QCss::Value cssValue = decl.d->values.first();
+ QString value = cssValue.toString();
lineHeight = value.toDouble(&ok);
if (ok) {
+ if (!hasOwnLineHeightType && cssValue.type == QCss::Value::Number) {
+ lineHeight *= 100.0;
+ hasLineHeightMultiplier = true;
+ }
lineHeightType = QTextBlockFormat::ProportionalHeight;
} else {
lineHeight = 0.0;
diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h
index 77bfa685c0..73dac38b82 100644
--- a/src/gui/text/qtexthtmlparser_p.h
+++ b/src/gui/text/qtexthtmlparser_p.h
@@ -173,6 +173,7 @@ struct QTextHtmlParserNode {
uint cssFloat : 2;
uint hasOwnListStyle : 1;
uint hasOwnLineHeightType : 1;
+ uint hasLineHeightMultiplier : 1;
uint hasCssListIndent : 1;
uint isEmptyParagraph : 1;
uint isTextFrame : 1;
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index cc91c107f9..066f258ea3 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -167,7 +167,7 @@ QRectF QTextInlineObject::rect() const
*/
qreal QTextInlineObject::width() const
{
- return eng->layoutData->items[itm].width.toReal();
+ return eng->layoutData->items.at(itm).width.toReal();
}
/*!
@@ -177,7 +177,7 @@ qreal QTextInlineObject::width() const
*/
qreal QTextInlineObject::ascent() const
{
- return eng->layoutData->items[itm].ascent.toReal();
+ return eng->layoutData->items.at(itm).ascent.toReal();
}
/*!
@@ -187,7 +187,7 @@ qreal QTextInlineObject::ascent() const
*/
qreal QTextInlineObject::descent() const
{
- return eng->layoutData->items[itm].descent.toReal();
+ return eng->layoutData->items.at(itm).descent.toReal();
}
/*!
@@ -198,7 +198,7 @@ qreal QTextInlineObject::descent() const
*/
qreal QTextInlineObject::height() const
{
- return eng->layoutData->items[itm].height().toReal();
+ return eng->layoutData->items.at(itm).height().toReal();
}
/*!
@@ -924,7 +924,7 @@ QRectF QTextLayout::boundingRect() const
QFixed ymin = d->lines.at(0).y;
for (int i = 0; i < d->lines.size(); ++i) {
- const QScriptLine &si = d->lines[i];
+ const QScriptLine &si = d->lines.at(i);
xmin = qMin(xmin, si.x);
ymin = qMin(ymin, si.y);
QFixed lineWidth = si.width < QFIXED_MAX ? qMax(si.width, si.textWidth) : si.textWidth;
@@ -1052,9 +1052,9 @@ QList<QGlyphRun> QTextLayout::glyphRuns(int from, int length) const
QHash<QPair<QFontEngine *, int>, QGlyphRun> glyphRunHash;
for (int i=0; i<d->lines.size(); ++i) {
- if (d->lines[i].from > from + length)
+ if (d->lines.at(i).from > from + length)
break;
- else if (d->lines[i].from + d->lines[i].length >= from) {
+ else if (d->lines.at(i).from + d->lines[i].length >= from) {
QList<QGlyphRun> glyphRuns = QTextLine(i, d).glyphRuns(from, length);
for (int j = 0; j < glyphRuns.size(); j++) {
@@ -1115,7 +1115,7 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang
int lastLine = d->lines.size();
for (int i = 0; i < d->lines.size(); ++i) {
QTextLine l(i, d);
- const QScriptLine &sl = d->lines[i];
+ const QScriptLine &sl = d->lines.at(i);
if (sl.y > clipe) {
lastLine = i;
@@ -1137,7 +1137,7 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang
region.setFillRule(Qt::WindingFill);
for (int line = firstLine; line < lastLine; ++line) {
- const QScriptLine &sl = d->lines[line];
+ const QScriptLine &sl = d->lines.at(line);
QTextLine tl(line, d);
QRectF lineRect(tl.naturalTextRect());
@@ -1302,7 +1302,7 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
return;
QTextLine l(line, d);
- const QScriptLine &sl = d->lines[line];
+ const QScriptLine &sl = d->lines.at(line);
qreal x = position.x() + l.cursorToX(cursorPosition);
@@ -1415,7 +1415,7 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
*/
QRectF QTextLine::rect() const
{
- const QScriptLine& sl = eng->lines[index];
+ const QScriptLine& sl = eng->lines.at(index);
return QRectF(sl.x.toReal(), sl.y.toReal(), sl.width.toReal(), sl.height().toReal());
}
@@ -1424,7 +1424,7 @@ QRectF QTextLine::rect() const
*/
QRectF QTextLine::naturalTextRect() const
{
- const QScriptLine& sl = eng->lines[index];
+ const QScriptLine& sl = eng->lines.at(index);
QFixed x = sl.x + eng->alignLine(sl);
QFixed width = sl.textWidth;
@@ -1441,7 +1441,7 @@ QRectF QTextLine::naturalTextRect() const
*/
qreal QTextLine::x() const
{
- return eng->lines[index].x.toReal();
+ return eng->lines.at(index).x.toReal();
}
/*!
@@ -1451,7 +1451,7 @@ qreal QTextLine::x() const
*/
qreal QTextLine::y() const
{
- return eng->lines[index].y.toReal();
+ return eng->lines.at(index).y.toReal();
}
/*!
@@ -1461,7 +1461,7 @@ qreal QTextLine::y() const
*/
qreal QTextLine::width() const
{
- return eng->lines[index].width.toReal();
+ return eng->lines.at(index).width.toReal();
}
@@ -1472,7 +1472,7 @@ qreal QTextLine::width() const
*/
qreal QTextLine::ascent() const
{
- return eng->lines[index].ascent.toReal();
+ return eng->lines.at(index).ascent.toReal();
}
/*!
@@ -1482,7 +1482,7 @@ qreal QTextLine::ascent() const
*/
qreal QTextLine::descent() const
{
- return eng->lines[index].descent.toReal();
+ return eng->lines.at(index).descent.toReal();
}
/*!
@@ -1494,7 +1494,7 @@ qreal QTextLine::descent() const
*/
qreal QTextLine::height() const
{
- return eng->lines[index].height().ceil().toReal();
+ return eng->lines.at(index).height().ceil().toReal();
}
/*!
@@ -1506,7 +1506,7 @@ qreal QTextLine::height() const
*/
qreal QTextLine::leading() const
{
- return eng->lines[index].leading.toReal();
+ return eng->lines.at(index).leading.toReal();
}
/*!
@@ -1541,7 +1541,7 @@ void QTextLine::setLeadingIncluded(bool included)
*/
bool QTextLine::leadingIncluded() const
{
- return eng->lines[index].leadingIncluded;
+ return eng->lines.at(index).leadingIncluded;
}
/*!
@@ -1551,7 +1551,7 @@ bool QTextLine::leadingIncluded() const
*/
qreal QTextLine::naturalTextWidth() const
{
- return eng->lines[index].textWidth.toReal();
+ return eng->lines.at(index).textWidth.toReal();
}
/*!
@@ -1566,7 +1566,7 @@ qreal QTextLine::naturalTextWidth() const
*/
qreal QTextLine::horizontalAdvance() const
{
- return eng->lines[index].textAdvance.toReal();
+ return eng->lines.at(index).textAdvance.toReal();
}
/*!
@@ -1832,7 +1832,7 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.softHyphenWidth = 0;
if (newItem != item) {
item = newItem;
- const QScriptItem &current = eng->layoutData->items[item];
+ const QScriptItem &current = eng->layoutData->items.at(item);
if (!current.num_glyphs) {
eng->shape(item);
attributes = eng->attributes();
@@ -1850,7 +1850,7 @@ void QTextLine::layout_helper(int maxGlyphs)
QFixed::fromReal(fontEngine->minRightBearing()));
}
}
- const QScriptItem &current = eng->layoutData->items[item];
+ const QScriptItem &current = eng->layoutData->items.at(item);
lbh.tmpData.leading = qMax(lbh.tmpData.leading + lbh.tmpData.ascent,
current.leading + current.ascent) - qMax(lbh.tmpData.ascent,
@@ -2093,7 +2093,7 @@ void QTextLine::setPosition(const QPointF &pos)
*/
QPointF QTextLine::position() const
{
- return QPointF(eng->lines[index].x.toReal(), eng->lines[index].y.toReal());
+ return QPointF(eng->lines.at(index).x.toReal(), eng->lines.at(index).y.toReal());
}
// ### DOC: I have no idea what this means/does.
@@ -2109,7 +2109,7 @@ QPointF QTextLine::position() const
*/
int QTextLine::textStart() const
{
- return eng->lines[index].from;
+ return eng->lines.at(index).from;
}
/*!
@@ -2121,9 +2121,9 @@ int QTextLine::textLength() const
{
if (eng->option.flags() & QTextOption::ShowLineAndParagraphSeparators
&& eng->block.isValid() && index == eng->lines.count()-1) {
- return eng->lines[index].length - 1;
+ return eng->lines.at(index).length - 1;
}
- return eng->lines[index].length + eng->lines[index].trailingSpaces;
+ return eng->lines.at(index).length + eng->lines.at(index).trailingSpaces;
}
static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const QTextCharFormat &chf, const QRectF &r)
@@ -2247,7 +2247,7 @@ static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine,
*/
QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
{
- const QScriptLine &line = eng->lines[index];
+ const QScriptLine &line = eng->lines.at(index);
if (line.length == 0)
return QList<QGlyphRun>();
diff --git a/src/gui/text/qtextoption.cpp b/src/gui/text/qtextoption.cpp
index 87e31eeb2c..2a16f50f33 100644
--- a/src/gui/text/qtextoption.cpp
+++ b/src/gui/text/qtextoption.cpp
@@ -144,7 +144,7 @@ QTextOption &QTextOption::operator=(const QTextOption &o)
Sets the tab positions for the text layout to those specified by
\a tabStops.
- \sa tabArray(), setTabStop(), setTabs()
+ \sa tabArray(), setTabStopDistance(), setTabs()
*/
void QTextOption::setTabArray(const QList<qreal> &tabStops)
{
@@ -332,22 +332,45 @@ QList<QTextOption::Tab> QTextOption::tabs() const
\sa flags()
*/
+#if QT_DEPRECATED_SINCE(5, 10)
/*!
\fn qreal QTextOption::tabStop() const
+ \deprecated in Qt 5.10. Use tabStopDistance() instead.
Returns the distance in device units between tab stops.
Convenient function for the above method
- \sa setTabStop(), tabArray(), setTabs(), tabs()
+ \sa setTabStopDistance(), tabArray(), setTabs(), tabs()
*/
/*!
\fn void QTextOption::setTabStop(qreal tabStop)
+ \deprecated in Qt 5.10. Use setTabStopDistance() instead.
Sets the default distance in device units between tab stops to the value specified
by \a tabStop.
- \sa tabStop(), setTabArray(), setTabs(), tabs()
+ \sa tabStopDistance(), setTabArray(), setTabs(), tabs()
+*/
+#endif
+
+/*!
+ \fn qreal QTextOption::tabStopDistance() const
+ \since 5.10
+
+ Returns the distance in device units between tab stops.
+
+ \sa setTabStopDistance(), tabArray(), setTabs(), tabs()
+*/
+
+/*!
+ \fn void QTextOption::setTabStopDistance(qreal tabStopDistance)
+ \since 5.10
+
+ Sets the default distance in device units between tab stops to the value specified
+ by \a tabStopDistance.
+
+ \sa tabStopDistance(), setTabArray(), setTabs(), tabs()
*/
/*!
@@ -426,7 +449,7 @@ QList<QTextOption::Tab> QTextOption::tabs() const
\fn void setTabs(const QList<Tab> &tabStops)
Set the Tab properties to \a tabStops.
- \sa tabStop(), tabs()
+ \sa tabStopDistance(), tabs()
*/
/*!
@@ -434,7 +457,7 @@ QList<QTextOption::Tab> QTextOption::tabs() const
\fn QList<QTextOption::Tab> QTextOption::tabs() const
Returns a list of tab positions defined for the text layout.
- \sa tabStop(), setTabs(), setTabStop()
+ \sa tabStopDistance(), setTabs(), setTabStop()
*/
diff --git a/src/gui/text/qtextoption.h b/src/gui/text/qtextoption.h
index 9ef9cee9bb..8b57278633 100644
--- a/src/gui/text/qtextoption.h
+++ b/src/gui/text/qtextoption.h
@@ -117,8 +117,13 @@ public:
inline void setFlags(Flags flags);
inline Flags flags() const { return Flags(f); }
- inline void setTabStop(qreal tabStop);
- inline qreal tabStop() const { return tab; }
+#if QT_DEPRECATED_SINCE(5, 10)
+ QT_DEPRECATED inline void setTabStop(qreal tabStop);
+ QT_DEPRECATED inline qreal tabStop() const { return tabStopDistance(); }
+#endif
+
+ inline void setTabStopDistance(qreal tabStopDistance);
+ inline qreal tabStopDistance() const { return tab; }
void setTabArray(const QList<qreal> &tabStops);
QList<qreal> tabArray() const;
@@ -149,7 +154,12 @@ inline void QTextOption::setAlignment(Qt::Alignment aalignment)
inline void QTextOption::setFlags(Flags aflags)
{ f = aflags; }
+#if QT_DEPRECATED_SINCE(5, 10)
inline void QTextOption::setTabStop(qreal atabStop)
+{ setTabStopDistance(atabStop); }
+#endif
+
+inline void QTextOption::setTabStopDistance(qreal atabStop)
{ tab = atabStop; }
QT_END_NAMESPACE
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index c9747877f7..77ccc02aa5 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -177,6 +177,19 @@ void QOpenUrlHandlerRegistry::handlerDestroyed(QObject *handler)
still fail to launch or fail to open the requested URL. This result will not be reported back
to the application.
+ \warning URLs passed to this function on iOS will not load unless their schemes are
+ listed in the \c LSApplicationQueriesSchemes key of the application's Info.plist file.
+ For more information, see the Apple Developer Documentation for
+ \l{https://developer.apple.com/documentation/uikit/uiapplication/1622952-canopenurl}{canOpenURL(_:)}.
+ For example, the following lines enable URLs with the HTTPS scheme:
+
+ \code
+ <key>LSApplicationQueriesSchemes</key>
+ <array>
+ <string>https</string>
+ </array>
+ \endcode
+
\sa setUrlHandler()
*/
bool QDesktopServices::openUrl(const QUrl &url)
diff --git a/src/gui/util/qshaderformat.cpp b/src/gui/util/qshaderformat.cpp
new file mode 100644
index 0000000000..373bfb9e7e
--- /dev/null
+++ b/src/gui/util/qshaderformat.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshaderformat_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QShaderFormat::QShaderFormat() Q_DECL_NOTHROW
+ : m_api(NoApi)
+{
+}
+
+QShaderFormat::Api QShaderFormat::api() const Q_DECL_NOTHROW
+{
+ return m_api;
+}
+
+void QShaderFormat::setApi(QShaderFormat::Api api) Q_DECL_NOTHROW
+{
+ m_api = api;
+}
+
+QVersionNumber QShaderFormat::version() const Q_DECL_NOTHROW
+{
+ return m_version;
+}
+
+void QShaderFormat::setVersion(const QVersionNumber &version) Q_DECL_NOTHROW
+{
+ m_version = version;
+}
+
+QStringList QShaderFormat::extensions() const Q_DECL_NOTHROW
+{
+ return m_extensions;
+}
+
+void QShaderFormat::setExtensions(const QStringList &extensions) Q_DECL_NOTHROW
+{
+ m_extensions = extensions;
+ m_extensions.sort();
+}
+
+QString QShaderFormat::vendor() const Q_DECL_NOTHROW
+{
+ return m_vendor;
+}
+
+void QShaderFormat::setVendor(const QString &vendor) Q_DECL_NOTHROW
+{
+ m_vendor = vendor;
+}
+
+bool QShaderFormat::isValid() const Q_DECL_NOTHROW
+{
+ return m_api != NoApi && m_version.majorVersion() > 0;
+}
+
+bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW
+{
+ if (!isValid() || !other.isValid())
+ return false;
+
+ if (m_api == OpenGLES && m_api != other.m_api)
+ return false;
+
+ if (m_api == OpenGLCoreProfile && m_api != other.m_api)
+ return false;
+
+ if (m_version < other.m_version)
+ return false;
+
+ const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(),
+ m_extensions.constEnd(),
+ other.m_extensions.constBegin(),
+ other.m_extensions.constEnd());
+ if (!containsAllExtensionsFromOther)
+ return false;
+
+ if (!other.m_vendor.isEmpty() && m_vendor != other.m_vendor)
+ return false;
+
+ return true;
+}
+
+bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW
+{
+ return lhs.api() == rhs.api()
+ && lhs.version() == rhs.version()
+ && lhs.extensions() == rhs.extensions()
+ && lhs.vendor() == rhs.vendor();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshaderformat_p.h b/src/gui/util/qshaderformat_p.h
new file mode 100644
index 0000000000..064c2364a7
--- /dev/null
+++ b/src/gui/util/qshaderformat_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERFORMAT_P_H
+#define QSHADERFORMAT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qversionnumber.h>
+
+QT_BEGIN_NAMESPACE
+
+class QShaderFormat
+{
+public:
+ enum Api : int {
+ NoApi,
+ OpenGLNoProfile,
+ OpenGLCoreProfile,
+ OpenGLCompatibilityProfile,
+ OpenGLES
+ };
+
+ Q_GUI_EXPORT QShaderFormat() Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT Api api() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setApi(Api api) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QVersionNumber version() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setVersion(const QVersionNumber &version) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QStringList extensions() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setExtensions(const QStringList &extensions) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QString vendor() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setVendor(const QString &vendor) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT bool isValid() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT bool supports(const QShaderFormat &other) const Q_DECL_NOTHROW;
+
+private:
+ Api m_api;
+ QVersionNumber m_version;
+ QStringList m_extensions;
+ QString m_vendor;
+};
+
+Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW;
+
+inline bool operator!=(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+Q_DECLARE_TYPEINFO(QShaderFormat, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QShaderFormat)
+
+#endif // QSHADERFORMAT_P_H
diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp
new file mode 100644
index 0000000000..31c2f74746
--- /dev/null
+++ b/src/gui/util/qshadergenerator.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshadergenerator_p.h"
+
+#include "qshaderlanguage_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ QByteArray toGlsl(QShaderLanguage::StorageQualifier qualifier, const QShaderFormat &format)
+ {
+ if (format.version().majorVersion() <= 2) {
+ // Note we're assuming fragment shader only here, it'd be different
+ // values for vertex shader, will need to be fixed properly at some
+ // point but isn't necessary yet (this problem already exists in past
+ // commits anyway)
+ switch (qualifier) {
+ case QShaderLanguage::Const:
+ return "const";
+ case QShaderLanguage::Input:
+ return "varying";
+ case QShaderLanguage::Output:
+ return ""; // Although fragment shaders for <=2 only have fixed outputs
+ case QShaderLanguage::Uniform:
+ return "uniform";
+ }
+ } else {
+ switch (qualifier) {
+ case QShaderLanguage::Const:
+ return "const";
+ case QShaderLanguage::Input:
+ return "in";
+ case QShaderLanguage::Output:
+ return "out";
+ case QShaderLanguage::Uniform:
+ return "uniform";
+ }
+ }
+
+ Q_UNREACHABLE();
+ }
+
+ QByteArray toGlsl(QShaderLanguage::VariableType type)
+ {
+ switch (type) {
+ case QShaderLanguage::Bool:
+ return "bool";
+ case QShaderLanguage::Int:
+ return "int";
+ case QShaderLanguage::Uint:
+ return "uint";
+ case QShaderLanguage::Float:
+ return "float";
+ case QShaderLanguage::Double:
+ return "double";
+ case QShaderLanguage::Vec2:
+ return "vec2";
+ case QShaderLanguage::Vec3:
+ return "vec3";
+ case QShaderLanguage::Vec4:
+ return "vec4";
+ case QShaderLanguage::DVec2:
+ return "dvec2";
+ case QShaderLanguage::DVec3:
+ return "dvec3";
+ case QShaderLanguage::DVec4:
+ return "dvec4";
+ case QShaderLanguage::BVec2:
+ return "bvec2";
+ case QShaderLanguage::BVec3:
+ return "bvec3";
+ case QShaderLanguage::BVec4:
+ return "bvec4";
+ case QShaderLanguage::IVec2:
+ return "ivec2";
+ case QShaderLanguage::IVec3:
+ return "ivec3";
+ case QShaderLanguage::IVec4:
+ return "ivec4";
+ case QShaderLanguage::UVec2:
+ return "uvec2";
+ case QShaderLanguage::UVec3:
+ return "uvec3";
+ case QShaderLanguage::UVec4:
+ return "uvec4";
+ case QShaderLanguage::Mat2:
+ return "mat2";
+ case QShaderLanguage::Mat3:
+ return "mat3";
+ case QShaderLanguage::Mat4:
+ return "mat4";
+ case QShaderLanguage::Mat2x2:
+ return "mat2x2";
+ case QShaderLanguage::Mat2x3:
+ return "mat2x3";
+ case QShaderLanguage::Mat2x4:
+ return "mat2x4";
+ case QShaderLanguage::Mat3x2:
+ return "mat3x2";
+ case QShaderLanguage::Mat3x3:
+ return "mat3x3";
+ case QShaderLanguage::Mat3x4:
+ return "mat3x4";
+ case QShaderLanguage::Mat4x2:
+ return "mat4x2";
+ case QShaderLanguage::Mat4x3:
+ return "mat4x3";
+ case QShaderLanguage::Mat4x4:
+ return "mat4x4";
+ case QShaderLanguage::DMat2:
+ return "dmat2";
+ case QShaderLanguage::DMat3:
+ return "dmat3";
+ case QShaderLanguage::DMat4:
+ return "dmat4";
+ case QShaderLanguage::DMat2x2:
+ return "dmat2x2";
+ case QShaderLanguage::DMat2x3:
+ return "dmat2x3";
+ case QShaderLanguage::DMat2x4:
+ return "dmat2x4";
+ case QShaderLanguage::DMat3x2:
+ return "dmat3x2";
+ case QShaderLanguage::DMat3x3:
+ return "dmat3x3";
+ case QShaderLanguage::DMat3x4:
+ return "dmat3x4";
+ case QShaderLanguage::DMat4x2:
+ return "dmat4x2";
+ case QShaderLanguage::DMat4x3:
+ return "dmat4x3";
+ case QShaderLanguage::DMat4x4:
+ return "dmat4x4";
+ case QShaderLanguage::Sampler1D:
+ return "sampler1D";
+ case QShaderLanguage::Sampler2D:
+ return "sampler2D";
+ case QShaderLanguage::Sampler3D:
+ return "sampler3D";
+ case QShaderLanguage::SamplerCube:
+ return "samplerCube";
+ case QShaderLanguage::Sampler2DRect:
+ return "sampler2DRect";
+ case QShaderLanguage::Sampler2DMs:
+ return "sampler2DMS";
+ case QShaderLanguage::SamplerBuffer:
+ return "samplerBuffer";
+ case QShaderLanguage::Sampler1DArray:
+ return "sampler1DArray";
+ case QShaderLanguage::Sampler2DArray:
+ return "sampler2DArray";
+ case QShaderLanguage::Sampler2DMsArray:
+ return "sampler2DMSArray";
+ case QShaderLanguage::SamplerCubeArray:
+ return "samplerCubeArray";
+ case QShaderLanguage::Sampler1DShadow:
+ return "sampler1DShadow";
+ case QShaderLanguage::Sampler2DShadow:
+ return "sampler2DShadow";
+ case QShaderLanguage::Sampler2DRectShadow:
+ return "sampler2DRectShadow";
+ case QShaderLanguage::Sampler1DArrayShadow:
+ return "sampler1DArrayShadow";
+ case QShaderLanguage::Sampler2DArrayShadow:
+ return "sample2DArrayShadow";
+ case QShaderLanguage::SamplerCubeShadow:
+ return "samplerCubeShadow";
+ case QShaderLanguage::SamplerCubeArrayShadow:
+ return "samplerCubeArrayShadow";
+ case QShaderLanguage::ISampler1D:
+ return "isampler1D";
+ case QShaderLanguage::ISampler2D:
+ return "isampler2D";
+ case QShaderLanguage::ISampler3D:
+ return "isampler3D";
+ case QShaderLanguage::ISamplerCube:
+ return "isamplerCube";
+ case QShaderLanguage::ISampler2DRect:
+ return "isampler2DRect";
+ case QShaderLanguage::ISampler2DMs:
+ return "isampler2DMS";
+ case QShaderLanguage::ISamplerBuffer:
+ return "isamplerBuffer";
+ case QShaderLanguage::ISampler1DArray:
+ return "isampler1DArray";
+ case QShaderLanguage::ISampler2DArray:
+ return "isampler2DArray";
+ case QShaderLanguage::ISampler2DMsArray:
+ return "isampler2DMSArray";
+ case QShaderLanguage::ISamplerCubeArray:
+ return "isamplerCubeArray";
+ case QShaderLanguage::USampler1D:
+ return "usampler1D";
+ case QShaderLanguage::USampler2D:
+ return "usampler2D";
+ case QShaderLanguage::USampler3D:
+ return "usampler3D";
+ case QShaderLanguage::USamplerCube:
+ return "usamplerCube";
+ case QShaderLanguage::USampler2DRect:
+ return "usampler2DRect";
+ case QShaderLanguage::USampler2DMs:
+ return "usampler2DMS";
+ case QShaderLanguage::USamplerBuffer:
+ return "usamplerBuffer";
+ case QShaderLanguage::USampler1DArray:
+ return "usampler1DArray";
+ case QShaderLanguage::USampler2DArray:
+ return "usampler2DArray";
+ case QShaderLanguage::USampler2DMsArray:
+ return "usampler2DMSArray";
+ case QShaderLanguage::USamplerCubeArray:
+ return "usamplerCubeArray";
+ }
+
+ Q_UNREACHABLE();
+ }
+
+ QByteArray replaceParameters(const QByteArray &original, const QShaderNode &node, const QShaderFormat &format)
+ {
+ auto result = original;
+
+ for (const auto &parameterName : node.parameterNames()) {
+ const auto placeholder = QByteArray(QByteArrayLiteral("$") + parameterName.toUtf8());
+ const auto parameter = node.parameter(parameterName);
+ if (parameter.userType() == qMetaTypeId<QShaderLanguage::StorageQualifier>()) {
+ const auto qualifier = parameter.value<QShaderLanguage::StorageQualifier>();
+ const auto value = toGlsl(qualifier, format);
+ result.replace(placeholder, value);
+ } else if (parameter.userType() == qMetaTypeId<QShaderLanguage::VariableType>()) {
+ const auto type = parameter.value<QShaderLanguage::VariableType>();
+ const auto value = toGlsl(type);
+ result.replace(placeholder, value);
+ } else {
+ const auto value = parameter.toString().toUtf8();
+ result.replace(placeholder, value);
+ }
+ }
+
+ return result;
+ }
+}
+
+QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) const
+{
+ auto code = QByteArrayList();
+
+ if (format.isValid()) {
+ const auto isGLES = format.api() == QShaderFormat::OpenGLES;
+ const auto major = format.version().majorVersion();
+ const auto minor = format.version().minorVersion();
+
+ const auto version = major == 2 && isGLES ? 100
+ : major == 3 && isGLES ? 300
+ : major == 2 ? 100 + 10 * (minor + 1)
+ : major == 3 && minor <= 2 ? 100 + 10 * (minor + 3)
+ : major * 100 + minor * 10;
+
+ const auto profile = isGLES && version > 100 ? QByteArrayLiteral(" es")
+ : version >= 150 && format.api() == QShaderFormat::OpenGLCoreProfile ? QByteArrayLiteral(" core")
+ : version >= 150 && format.api() == QShaderFormat::OpenGLCompatibilityProfile ? QByteArrayLiteral(" compatibility")
+ : QByteArray();
+
+ code << (QByteArrayLiteral("#version ") + QByteArray::number(version) + profile);
+ code << QByteArray();
+ }
+
+ const auto intersectsEnabledLayers = [enabledLayers] (const QStringList &layers) {
+ return layers.isEmpty()
+ || std::any_of(layers.cbegin(), layers.cend(),
+ [enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
+ };
+
+ for (const auto &node : graph.nodes()) {
+ if (intersectsEnabledLayers(node.layers())) {
+ for (const auto &snippet : node.rule(format).headerSnippets) {
+ code << replaceParameters(snippet, node, format);
+ }
+ }
+ }
+
+ code << QByteArray();
+ code << QByteArrayLiteral("void main()");
+ code << QByteArrayLiteral("{");
+
+ for (const auto &statement : graph.createStatements(enabledLayers)) {
+ const auto node = statement.node;
+ auto line = node.rule(format).substitution;
+ for (const auto &port : node.ports()) {
+ const auto portName = port.name;
+ const auto portDirection = port.direction;
+ const auto isInput = port.direction == QShaderNodePort::Input;
+
+ const auto portIndex = statement.portIndex(portDirection, portName);
+ const auto variableIndex = isInput ? statement.inputs.at(portIndex)
+ : statement.outputs.at(portIndex);
+ if (variableIndex < 0)
+ continue;
+
+ const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8());
+ const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex));
+ line.replace(placeholder, variable);
+ }
+
+ code << QByteArrayLiteral(" ") + replaceParameters(line, node, format);
+ }
+
+ code << QByteArrayLiteral("}");
+ code << QByteArray();
+ return code.join('\n');
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshadergenerator_p.h b/src/gui/util/qshadergenerator_p.h
new file mode 100644
index 0000000000..7bc8838b52
--- /dev/null
+++ b/src/gui/util/qshadergenerator_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERGENERATOR_P_H
+#define QSHADERGENERATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtGui/private/qshadergraph_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QShaderGenerator
+{
+public:
+ Q_GUI_EXPORT QByteArray createShaderCode(const QStringList &enabledLayers = QStringList()) const;
+
+ QShaderGraph graph;
+ QShaderFormat format;
+};
+
+Q_DECLARE_TYPEINFO(QShaderGenerator, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QShaderGenerator)
+
+#endif // QSHADERGENERATOR_P_H
diff --git a/src/gui/util/qshadergraph.cpp b/src/gui/util/qshadergraph.cpp
new file mode 100644
index 0000000000..828c709a12
--- /dev/null
+++ b/src/gui/util/qshadergraph.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshadergraph_p.h"
+
+QT_BEGIN_NAMESPACE
+
+
+namespace
+{
+ QVector<QShaderNode> copyOutputNodes(const QVector<QShaderNode> &nodes)
+ {
+ auto res = QVector<QShaderNode>();
+ std::copy_if(nodes.cbegin(), nodes.cend(),
+ std::back_inserter(res),
+ [] (const QShaderNode &node) {
+ return node.type() == QShaderNode::Output;
+ });
+ return res;
+ }
+
+ QVector<QShaderGraph::Edge> incomingEdges(const QVector<QShaderGraph::Edge> &edges, const QUuid &uuid)
+ {
+ auto res = QVector<QShaderGraph::Edge>();
+ std::copy_if(edges.cbegin(), edges.cend(),
+ std::back_inserter(res),
+ [uuid] (const QShaderGraph::Edge &edge) {
+ return edge.sourceNodeUuid == uuid;
+ });
+ return res;
+ }
+
+ QVector<QShaderGraph::Edge> outgoingEdges(const QVector<QShaderGraph::Edge> &edges, const QUuid &uuid)
+ {
+ auto res = QVector<QShaderGraph::Edge>();
+ std::copy_if(edges.cbegin(), edges.cend(),
+ std::back_inserter(res),
+ [uuid] (const QShaderGraph::Edge &edge) {
+ return edge.targetNodeUuid == uuid;
+ });
+ return res;
+ }
+
+ QShaderGraph::Statement nodeToStatement(const QShaderNode &node, int &nextVarId)
+ {
+ auto statement = QShaderGraph::Statement();
+ statement.node = node;
+
+ const auto ports = node.ports();
+ for (const auto &port : ports) {
+ if (port.direction == QShaderNodePort::Input) {
+ statement.inputs.append(-1);
+ } else {
+ statement.outputs.append(nextVarId);
+ nextVarId++;
+ }
+ }
+ return statement;
+ }
+
+ QShaderGraph::Statement completeStatement(const QHash<QUuid, QShaderGraph::Statement> &idHash,
+ const QVector<QShaderGraph::Edge> edges,
+ const QUuid &uuid)
+ {
+ auto targetStatement = idHash.value(uuid);
+ for (const auto &edge : edges) {
+ if (edge.targetNodeUuid != uuid)
+ continue;
+
+ const auto sourceStatement = idHash.value(edge.sourceNodeUuid);
+ const auto sourcePortIndex = sourceStatement.portIndex(QShaderNodePort::Output, edge.sourcePortName);
+ const auto targetPortIndex = targetStatement.portIndex(QShaderNodePort::Input, edge.targetPortName);
+
+ if (sourcePortIndex < 0 || targetPortIndex < 0)
+ continue;
+
+ const auto &sourceOutputs = sourceStatement.outputs;
+ auto &targetInputs = targetStatement.inputs;
+ targetInputs[targetPortIndex] = sourceOutputs[sourcePortIndex];
+ }
+ return targetStatement;
+ }
+}
+
+QUuid QShaderGraph::Statement::uuid() const Q_DECL_NOTHROW
+{
+ return node.uuid();
+}
+
+int QShaderGraph::Statement::portIndex(QShaderNodePort::Direction direction, const QString &portName) const Q_DECL_NOTHROW
+{
+ const auto ports = node.ports();
+ int index = 0;
+ for (const auto &port : ports) {
+ if (port.name == portName && port.direction == direction)
+ return index;
+ else if (port.direction == direction)
+ index++;
+ }
+ return -1;
+}
+
+void QShaderGraph::addNode(const QShaderNode &node)
+{
+ removeNode(node);
+ m_nodes.append(node);
+}
+
+void QShaderGraph::removeNode(const QShaderNode &node)
+{
+ const auto it = std::find_if(m_nodes.begin(), m_nodes.end(),
+ [node] (const QShaderNode &n) { return n.uuid() == node.uuid(); });
+ if (it != m_nodes.end())
+ m_nodes.erase(it);
+}
+
+QVector<QShaderNode> QShaderGraph::nodes() const Q_DECL_NOTHROW
+{
+ return m_nodes;
+}
+
+void QShaderGraph::addEdge(const QShaderGraph::Edge &edge)
+{
+ if (m_edges.contains(edge))
+ return;
+ m_edges.append(edge);
+}
+
+void QShaderGraph::removeEdge(const QShaderGraph::Edge &edge)
+{
+ m_edges.removeAll(edge);
+}
+
+QVector<QShaderGraph::Edge> QShaderGraph::edges() const Q_DECL_NOTHROW
+{
+ return m_edges;
+}
+
+QVector<QShaderGraph::Statement> QShaderGraph::createStatements(const QStringList &enabledLayers) const
+{
+ const auto intersectsEnabledLayers = [enabledLayers] (const QStringList &layers) {
+ return layers.isEmpty()
+ || std::any_of(layers.cbegin(), layers.cend(),
+ [enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
+ };
+
+ const auto enabledNodes = [this, intersectsEnabledLayers] {
+ auto res = QVector<QShaderNode>();
+ std::copy_if(m_nodes.cbegin(), m_nodes.cend(),
+ std::back_inserter(res),
+ [intersectsEnabledLayers] (const QShaderNode &node) {
+ return intersectsEnabledLayers(node.layers());
+ });
+ return res;
+ }();
+
+ const auto enabledEdges = [this, intersectsEnabledLayers] {
+ auto res = QVector<Edge>();
+ std::copy_if(m_edges.cbegin(), m_edges.cend(),
+ std::back_inserter(res),
+ [intersectsEnabledLayers] (const Edge &edge) {
+ return intersectsEnabledLayers(edge.layers);
+ });
+ return res;
+ }();
+
+ const auto idHash = [enabledNodes] {
+ auto nextVarId = 0;
+ auto res = QHash<QUuid, Statement>();
+ for (const auto &node : enabledNodes)
+ res.insert(node.uuid(), nodeToStatement(node, nextVarId));
+ return res;
+ }();
+
+ auto result = QVector<Statement>();
+ auto currentEdges = enabledEdges;
+ auto currentUuids = [enabledNodes] {
+ const auto inputs = copyOutputNodes(enabledNodes);
+ auto res = QVector<QUuid>();
+ std::transform(inputs.cbegin(), inputs.cend(),
+ std::back_inserter(res),
+ [](const QShaderNode &node) { return node.uuid(); });
+ return res;
+ }();
+
+ // Implements Kahn's algorithm to flatten the graph
+ // https://en.wikipedia.org/wiki/Topological_sorting#Kahn.27s_algorithm
+ //
+ // We implement it with a small twist though, we follow the edges backward
+ // because we want to track the dependencies from the output nodes and not the
+ // input nodes
+ while (!currentUuids.isEmpty()) {
+ const auto uuid = currentUuids.takeFirst();
+ result.append(completeStatement(idHash, enabledEdges, uuid));
+
+ const auto outgoing = outgoingEdges(currentEdges, uuid);
+ for (const auto &outgoingEdge : outgoing) {
+ currentEdges.removeAll(outgoingEdge);
+ const QUuid nextUuid = outgoingEdge.sourceNodeUuid;
+ const auto incoming = incomingEdges(currentEdges, nextUuid);
+ if (incoming.isEmpty()) {
+ currentUuids.append(nextUuid);
+ }
+ }
+ }
+
+ std::reverse(result.begin(), result.end());
+ return result;
+}
+
+bool operator==(const QShaderGraph::Edge &lhs, const QShaderGraph::Edge &rhs) Q_DECL_NOTHROW
+{
+ return lhs.sourceNodeUuid == rhs.sourceNodeUuid
+ && lhs.sourcePortName == rhs.sourcePortName
+ && lhs.targetNodeUuid == rhs.targetNodeUuid
+ && lhs.targetPortName == rhs.targetPortName;
+}
+
+bool operator==(const QShaderGraph::Statement &lhs, const QShaderGraph::Statement &rhs) Q_DECL_NOTHROW
+{
+ return lhs.inputs == rhs.inputs
+ && lhs.outputs == rhs.outputs
+ && lhs.node.uuid() == rhs.node.uuid();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshadergraph_p.h b/src/gui/util/qshadergraph_p.h
new file mode 100644
index 0000000000..756e1b2da2
--- /dev/null
+++ b/src/gui/util/qshadergraph_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERGRAPH_P_H
+#define QSHADERGRAPH_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtGui/private/qshadernode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QShaderGraph
+{
+public:
+ class Edge
+ {
+ public:
+ QStringList layers;
+ QUuid sourceNodeUuid;
+ QString sourcePortName;
+ QUuid targetNodeUuid;
+ QString targetPortName;
+ };
+
+ class Statement
+ {
+ public:
+ Q_GUI_EXPORT QUuid uuid() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT int portIndex(QShaderNodePort::Direction direction, const QString &portName) const Q_DECL_NOTHROW;
+
+ QShaderNode node;
+ QVector<int> inputs;
+ QVector<int> outputs;
+ };
+
+ Q_GUI_EXPORT void addNode(const QShaderNode &node);
+ Q_GUI_EXPORT void removeNode(const QShaderNode &node);
+ Q_GUI_EXPORT QVector<QShaderNode> nodes() const Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT void addEdge(const Edge &edge);
+ Q_GUI_EXPORT void removeEdge(const Edge &edge);
+ Q_GUI_EXPORT QVector<Edge> edges() const Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QVector<Statement> createStatements(const QStringList &enabledLayers = QStringList()) const;
+
+private:
+ QVector<QShaderNode> m_nodes;
+ QVector<Edge> m_edges;
+};
+
+Q_GUI_EXPORT bool operator==(const QShaderGraph::Edge &lhs, const QShaderGraph::Edge &rhs) Q_DECL_NOTHROW;
+
+inline bool operator!=(const QShaderGraph::Edge &lhs, const QShaderGraph::Edge &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+Q_GUI_EXPORT bool operator==(const QShaderGraph::Statement &lhs, const QShaderGraph::Statement &rhs) Q_DECL_NOTHROW;
+
+inline bool operator!=(const QShaderGraph::Statement &lhs, const QShaderGraph::Statement &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+Q_DECLARE_TYPEINFO(QShaderGraph, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QShaderGraph::Edge, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QShaderGraph::Statement, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QShaderGraph)
+Q_DECLARE_METATYPE(QShaderGraph::Edge)
+Q_DECLARE_METATYPE(QShaderGraph::Statement)
+
+#endif // QSHADERGRAPH_P_H
diff --git a/src/gui/util/qshadergraphloader.cpp b/src/gui/util/qshadergraphloader.cpp
new file mode 100644
index 0000000000..8d92c73a5a
--- /dev/null
+++ b/src/gui/util/qshadergraphloader.cpp
@@ -0,0 +1,254 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshadergraphloader_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+void qt_register_ShaderLanguage_enums();
+
+QShaderGraphLoader::QShaderGraphLoader() Q_DECL_NOTHROW
+ : m_status(Null),
+ m_device(nullptr)
+{
+ qt_register_ShaderLanguage_enums();
+}
+
+QShaderGraphLoader::Status QShaderGraphLoader::status() const Q_DECL_NOTHROW
+{
+ return m_status;
+}
+
+QShaderGraph QShaderGraphLoader::graph() const Q_DECL_NOTHROW
+{
+ return m_graph;
+}
+
+QIODevice *QShaderGraphLoader::device() const Q_DECL_NOTHROW
+{
+ return m_device;
+}
+
+void QShaderGraphLoader::setDevice(QIODevice *device) Q_DECL_NOTHROW
+{
+ m_device = device;
+ m_graph = QShaderGraph();
+ m_status = !m_device ? Null
+ : (m_device->openMode() & QIODevice::ReadOnly) ? Waiting
+ : Error;
+}
+
+QHash<QString, QShaderNode> QShaderGraphLoader::prototypes() const Q_DECL_NOTHROW
+{
+ return m_prototypes;
+}
+
+void QShaderGraphLoader::setPrototypes(const QHash<QString, QShaderNode> &prototypes) Q_DECL_NOTHROW
+{
+ m_prototypes = prototypes;
+}
+
+void QShaderGraphLoader::load()
+{
+ if (m_status == Error)
+ return;
+
+ auto error = QJsonParseError();
+ const auto document = QJsonDocument::fromJson(m_device->readAll(), &error);
+
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << "Invalid JSON document:" << error.errorString();
+ m_status = Error;
+ return;
+ }
+
+ if (document.isEmpty() || !document.isObject()) {
+ qWarning() << "Invalid JSON document, root should be an object";
+ m_status = Error;
+ return;
+ }
+
+ const auto root = document.object();
+
+ const auto nodesValue = root.value(QStringLiteral("nodes"));
+ if (!nodesValue.isArray()) {
+ qWarning() << "Invalid nodes property, should be an array";
+ m_status = Error;
+ return;
+ }
+
+ const auto edgesValue = root.value(QStringLiteral("edges"));
+ if (!edgesValue.isArray()) {
+ qWarning() << "Invalid edges property, should be an array";
+ m_status = Error;
+ return;
+ }
+
+ bool hasError = false;
+
+ const auto nodes = nodesValue.toArray();
+ for (const auto &nodeValue : nodes) {
+ if (!nodeValue.isObject()) {
+ qWarning() << "Invalid node found";
+ hasError = true;
+ continue;
+ }
+
+ const auto nodeObject = nodeValue.toObject();
+
+ const auto uuidString = nodeObject.value(QStringLiteral("uuid")).toString();
+ const auto uuid = QUuid(uuidString);
+ if (uuid.isNull()) {
+ qWarning() << "Invalid UUID found in node:" << uuidString;
+ hasError = true;
+ continue;
+ }
+
+ const auto type = nodeObject.value(QStringLiteral("type")).toString();
+ if (!m_prototypes.contains(type)) {
+ qWarning() << "Unsupported node type found:" << type;
+ hasError = true;
+ continue;
+ }
+
+ const auto layersArray = nodeObject.value(QStringLiteral("layers")).toArray();
+ auto layers = QStringList();
+ for (const auto &layerValue : layersArray) {
+ layers.append(layerValue.toString());
+ }
+
+ auto node = m_prototypes.value(type);
+ node.setUuid(uuid);
+ node.setLayers(layers);
+
+ const auto parametersValue = nodeObject.value(QStringLiteral("parameters"));
+ if (parametersValue.isObject()) {
+ const auto parametersObject = parametersValue.toObject();
+ for (const auto &parameterName : parametersObject.keys()) {
+ const auto parameterValue = parametersObject.value(parameterName);
+ if (parameterValue.isObject()) {
+ const auto parameterObject = parameterValue.toObject();
+ const auto type = parameterObject.value(QStringLiteral("type")).toString();
+ const auto typeId = QMetaType::type(type.toUtf8());
+
+ const auto value = parameterObject.value(QStringLiteral("value")).toString();
+ auto variant = QVariant(value);
+
+ if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
+ const auto metaObject = QMetaType::metaObjectForType(typeId);
+ const auto className = metaObject->className();
+ const auto enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
+ const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
+ const auto enumValue = metaEnum.keyToValue(value.toUtf8());
+ variant = QVariant(enumValue);
+ variant.convert(typeId);
+ } else {
+ variant.convert(typeId);
+ }
+ node.setParameter(parameterName, variant);
+ } else {
+ node.setParameter(parameterName, parameterValue.toVariant());
+ }
+ }
+ }
+
+ m_graph.addNode(node);
+ }
+
+ const auto edges = edgesValue.toArray();
+ for (const auto &edgeValue : edges) {
+ if (!edgeValue.isObject()) {
+ qWarning() << "Invalid edge found";
+ hasError = true;
+ continue;
+ }
+
+ const auto edgeObject = edgeValue.toObject();
+
+ const auto sourceUuidString = edgeObject.value(QStringLiteral("sourceUuid")).toString();
+ const auto sourceUuid = QUuid(sourceUuidString);
+ if (sourceUuid.isNull()) {
+ qWarning() << "Invalid source UUID found in edge:" << sourceUuidString;
+ hasError = true;
+ continue;
+ }
+
+ const auto sourcePort = edgeObject.value(QStringLiteral("sourcePort")).toString();
+
+ const auto targetUuidString = edgeObject.value(QStringLiteral("targetUuid")).toString();
+ const auto targetUuid = QUuid(targetUuidString);
+ if (targetUuid.isNull()) {
+ qWarning() << "Invalid target UUID found in edge:" << targetUuidString;
+ hasError = true;
+ continue;
+ }
+
+ const auto targetPort = edgeObject.value(QStringLiteral("targetPort")).toString();
+
+ const auto layersArray = edgeObject.value(QStringLiteral("layers")).toArray();
+ auto layers = QStringList();
+ for (const auto &layerValue : layersArray) {
+ layers.append(layerValue.toString());
+ }
+
+ auto edge = QShaderGraph::Edge();
+ edge.sourceNodeUuid = sourceUuid;
+ edge.sourcePortName = sourcePort;
+ edge.targetNodeUuid = targetUuid;
+ edge.targetPortName = targetPort;
+ edge.layers = layers;
+ m_graph.addEdge(edge);
+ }
+
+ if (hasError) {
+ m_status = Error;
+ m_graph = QShaderGraph();
+ } else {
+ m_status = Ready;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshadergraphloader_p.h b/src/gui/util/qshadergraphloader_p.h
new file mode 100644
index 0000000000..97cbd8d18c
--- /dev/null
+++ b/src/gui/util/qshadergraphloader_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERGRAPHLOADER_P_H
+#define QSHADERGRAPHLOADER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtGui/private/qshadergraph_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class QShaderGraphLoader
+{
+public:
+ enum Status : char {
+ Null,
+ Waiting,
+ Ready,
+ Error
+ };
+
+ Q_GUI_EXPORT QShaderGraphLoader() Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT Status status() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT QShaderGraph graph() const Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QIODevice *device() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setDevice(QIODevice *device) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QHash<QString, QShaderNode> prototypes() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setPrototypes(const QHash<QString, QShaderNode> &prototypes) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT void load();
+
+private:
+ Status m_status;
+ QIODevice *m_device;
+ QHash<QString, QShaderNode> m_prototypes;
+ QShaderGraph m_graph;
+};
+
+Q_DECLARE_TYPEINFO(QShaderGraphLoader, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QShaderGraphLoader)
+Q_DECLARE_METATYPE(QShaderGraphLoader::Status)
+
+#endif // QSHADERGRAPHLOADER_P_H
diff --git a/src/gui/util/qshaderlanguage.cpp b/src/gui/util/qshaderlanguage.cpp
new file mode 100644
index 0000000000..f9192f5ff3
--- /dev/null
+++ b/src/gui/util/qshaderlanguage.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Layouts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshaderlanguage_p.h"
+
+#include <QtCore/qcoreapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+// Note: to be invoked explicitly. Relying for example on
+// Q_COREAPP_STARTUP_FUNCTION would not be acceptable in static builds.
+void qt_register_ShaderLanguage_enums()
+{
+ qRegisterMetaType<QShaderLanguage::StorageQualifier>();
+ qRegisterMetaType<QShaderLanguage::VariableType>();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshaderlanguage_p.h b/src/gui/util/qshaderlanguage_p.h
new file mode 100644
index 0000000000..5c7819a3b8
--- /dev/null
+++ b/src/gui/util/qshaderlanguage_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Layouts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERLANGUAGE_P_H
+#define QSHADERLANGUAGE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QShaderLanguage
+{
+ Q_GUI_EXPORT Q_NAMESPACE
+
+ enum StorageQualifier : char {
+ Const = 1,
+ Input,
+ Output,
+ Uniform
+ };
+ Q_ENUM_NS(StorageQualifier)
+
+ enum VariableType : int {
+ Bool = 1,
+ Int,
+ Uint,
+ Float,
+ Double,
+ Vec2,
+ Vec3,
+ Vec4,
+ DVec2,
+ DVec3,
+ DVec4,
+ BVec2,
+ BVec3,
+ BVec4,
+ IVec2,
+ IVec3,
+ IVec4,
+ UVec2,
+ UVec3,
+ UVec4,
+ Mat2,
+ Mat3,
+ Mat4,
+ Mat2x2,
+ Mat2x3,
+ Mat2x4,
+ Mat3x2,
+ Mat3x3,
+ Mat3x4,
+ Mat4x2,
+ Mat4x3,
+ Mat4x4,
+ DMat2,
+ DMat3,
+ DMat4,
+ DMat2x2,
+ DMat2x3,
+ DMat2x4,
+ DMat3x2,
+ DMat3x3,
+ DMat3x4,
+ DMat4x2,
+ DMat4x3,
+ DMat4x4,
+ Sampler1D,
+ Sampler2D,
+ Sampler3D,
+ SamplerCube,
+ Sampler2DRect,
+ Sampler2DMs,
+ SamplerBuffer,
+ Sampler1DArray,
+ Sampler2DArray,
+ Sampler2DMsArray,
+ SamplerCubeArray,
+ Sampler1DShadow,
+ Sampler2DShadow,
+ Sampler2DRectShadow,
+ Sampler1DArrayShadow,
+ Sampler2DArrayShadow,
+ SamplerCubeShadow,
+ SamplerCubeArrayShadow,
+ ISampler1D,
+ ISampler2D,
+ ISampler3D,
+ ISamplerCube,
+ ISampler2DRect,
+ ISampler2DMs,
+ ISamplerBuffer,
+ ISampler1DArray,
+ ISampler2DArray,
+ ISampler2DMsArray,
+ ISamplerCubeArray,
+ USampler1D,
+ USampler2D,
+ USampler3D,
+ USamplerCube,
+ USampler2DRect,
+ USampler2DMs,
+ USamplerBuffer,
+ USampler1DArray,
+ USampler2DArray,
+ USampler2DMsArray,
+ USamplerCubeArray
+ };
+ Q_ENUM_NS(VariableType)
+}
+
+QT_END_NAMESPACE
+
+#endif // QSHADERLANGUAGE_P_H
diff --git a/src/gui/util/qshadernode.cpp b/src/gui/util/qshadernode.cpp
new file mode 100644
index 0000000000..676667ddcf
--- /dev/null
+++ b/src/gui/util/qshadernode.cpp
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Layouts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshadernode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QShaderNode::Type QShaderNode::type() const Q_DECL_NOTHROW
+{
+ int inputCount = 0;
+ int outputCount = 0;
+ for (const auto &port : qAsConst(m_ports)) {
+ switch (port.direction) {
+ case QShaderNodePort::Input:
+ inputCount++;
+ break;
+ case QShaderNodePort::Output:
+ outputCount++;
+ break;
+ }
+ }
+
+ return (inputCount == 0 && outputCount == 0) ? Invalid
+ : (inputCount > 0 && outputCount == 0) ? Output
+ : (inputCount == 0 && outputCount > 0) ? Input
+ : Function;
+}
+
+QUuid QShaderNode::uuid() const Q_DECL_NOTHROW
+{
+ return m_uuid;
+}
+
+void QShaderNode::setUuid(const QUuid &uuid) Q_DECL_NOTHROW
+{
+ m_uuid = uuid;
+}
+
+QStringList QShaderNode::layers() const Q_DECL_NOTHROW
+{
+ return m_layers;
+}
+
+void QShaderNode::setLayers(const QStringList &layers) Q_DECL_NOTHROW
+{
+ m_layers = layers;
+}
+
+QVector<QShaderNodePort> QShaderNode::ports() const Q_DECL_NOTHROW
+{
+ return m_ports;
+}
+
+void QShaderNode::addPort(const QShaderNodePort &port)
+{
+ removePort(port);
+ m_ports.append(port);
+}
+
+void QShaderNode::removePort(const QShaderNodePort &port)
+{
+ const auto it = std::find_if(m_ports.begin(), m_ports.end(),
+ [port](const QShaderNodePort &p) {
+ return p.name == port.name;
+ });
+ if (it != m_ports.end())
+ m_ports.erase(it);
+}
+
+QStringList QShaderNode::parameterNames() const
+{
+ return m_parameters.keys();
+}
+
+QVariant QShaderNode::parameter(const QString &name) const
+{
+ return m_parameters.value(name);
+}
+
+void QShaderNode::setParameter(const QString &name, const QVariant &value)
+{
+ m_parameters.insert(name, value);
+}
+
+void QShaderNode::clearParameter(const QString &name)
+{
+ m_parameters.remove(name);
+}
+
+void QShaderNode::addRule(const QShaderFormat &format, const QShaderNode::Rule &rule)
+{
+ removeRule(format);
+ m_rules << qMakePair(format, rule);
+}
+
+void QShaderNode::removeRule(const QShaderFormat &format)
+{
+ const auto it = std::find_if(m_rules.begin(), m_rules.end(),
+ [format](const QPair<QShaderFormat, Rule> &entry) {
+ return entry.first == format;
+ });
+ if (it != m_rules.end())
+ m_rules.erase(it);
+}
+
+QVector<QShaderFormat> QShaderNode::availableFormats() const
+{
+ auto res = QVector<QShaderFormat>();
+ std::transform(m_rules.cbegin(), m_rules.cend(),
+ std::back_inserter(res),
+ [](const QPair<QShaderFormat, Rule> &entry) { return entry.first; });
+ return res;
+}
+
+QShaderNode::Rule QShaderNode::rule(const QShaderFormat &format) const
+{
+ const auto it = std::find_if(m_rules.crbegin(), m_rules.crend(),
+ [format](const QPair<QShaderFormat, Rule> &entry) {
+ return format.supports(entry.first);
+ });
+ return it != m_rules.crend() ? it->second : Rule();
+}
+
+QShaderNode::Rule::Rule(const QByteArray &subs, const QByteArrayList &snippets) Q_DECL_NOTHROW
+ : substitution(subs),
+ headerSnippets(snippets)
+{
+}
+
+bool operator==(const QShaderNode::Rule &lhs, const QShaderNode::Rule &rhs) Q_DECL_NOTHROW
+{
+ return lhs.substitution == rhs.substitution
+ && lhs.headerSnippets == rhs.headerSnippets;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshadernode_p.h b/src/gui/util/qshadernode_p.h
new file mode 100644
index 0000000000..494c87bc18
--- /dev/null
+++ b/src/gui/util/qshadernode_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Layouts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERNODE_P_H
+#define QSHADERNODE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtGui/private/qshaderformat_p.h>
+#include <QtGui/private/qshadernodeport_p.h>
+
+#include <QtCore/quuid.h>
+
+QT_BEGIN_NAMESPACE
+
+class QShaderNode
+{
+public:
+ enum Type : char {
+ Invalid,
+ Input,
+ Output,
+ Function
+ };
+
+ class Rule
+ {
+ public:
+ Q_GUI_EXPORT Rule(const QByteArray &substitution = QByteArray(), const QByteArrayList &headerSnippets = QByteArrayList()) Q_DECL_NOTHROW;
+
+ QByteArray substitution;
+ QByteArrayList headerSnippets;
+ };
+
+ Q_GUI_EXPORT Type type() const Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QUuid uuid() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setUuid(const QUuid &uuid) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QStringList layers() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setLayers(const QStringList &layers) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QVector<QShaderNodePort> ports() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void addPort(const QShaderNodePort &port);
+ Q_GUI_EXPORT void removePort(const QShaderNodePort &port);
+
+ Q_GUI_EXPORT QStringList parameterNames() const;
+ Q_GUI_EXPORT QVariant parameter(const QString &name) const;
+ Q_GUI_EXPORT void setParameter(const QString &name, const QVariant &value);
+ Q_GUI_EXPORT void clearParameter(const QString &name);
+
+ Q_GUI_EXPORT void addRule(const QShaderFormat &format, const Rule &rule);
+ Q_GUI_EXPORT void removeRule(const QShaderFormat &format);
+
+ Q_GUI_EXPORT QVector<QShaderFormat> availableFormats() const;
+ Q_GUI_EXPORT Rule rule(const QShaderFormat &format) const;
+
+private:
+ QUuid m_uuid;
+ QStringList m_layers;
+ QVector<QShaderNodePort> m_ports;
+ QHash<QString, QVariant> m_parameters;
+ QVector<QPair<QShaderFormat, QShaderNode::Rule>> m_rules;
+};
+
+Q_GUI_EXPORT bool operator==(const QShaderNode::Rule &lhs, const QShaderNode::Rule &rhs) Q_DECL_NOTHROW;
+
+inline bool operator!=(const QShaderNode::Rule &lhs, const QShaderNode::Rule &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+Q_DECLARE_TYPEINFO(QShaderNode, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(QShaderNode::Rule, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QShaderNode)
+Q_DECLARE_METATYPE(QShaderNode::Rule)
+
+#endif // QSHADERNODE_P_H
diff --git a/src/gui/util/qshadernodeport.cpp b/src/gui/util/qshadernodeport.cpp
new file mode 100644
index 0000000000..03646a9467
--- /dev/null
+++ b/src/gui/util/qshadernodeport.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshadernodeport_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QShaderNodePort::QShaderNodePort() Q_DECL_NOTHROW
+ : direction(Output)
+{
+}
+
+bool operator==(const QShaderNodePort &lhs, const QShaderNodePort &rhs) Q_DECL_NOTHROW
+{
+ return lhs.direction == rhs.direction
+ && lhs.name == rhs.name;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshadernodeport_p.h b/src/gui/util/qshadernodeport_p.h
new file mode 100644
index 0000000000..cfdaf05017
--- /dev/null
+++ b/src/gui/util/qshadernodeport_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERNODEPORT_P_H
+#define QSHADERNODEPORT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtCore/qstring.h>
+#include <QtCore/qvariant.h>
+
+QT_BEGIN_NAMESPACE
+
+class QShaderNodePort
+{
+public:
+ enum Direction : char {
+ Input,
+ Output
+ };
+
+ Q_GUI_EXPORT QShaderNodePort() Q_DECL_NOTHROW;
+
+ QShaderNodePort::Direction direction;
+ QString name;
+};
+
+Q_GUI_EXPORT bool operator==(const QShaderNodePort &lhs, const QShaderNodePort &rhs) Q_DECL_NOTHROW;
+
+inline bool operator!=(const QShaderNodePort &lhs, const QShaderNodePort &rhs) Q_DECL_NOTHROW
+{
+ return !(lhs == rhs);
+}
+
+Q_DECLARE_TYPEINFO(QShaderNodePort, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QShaderNodePort)
+
+#endif // QSHADERNODEPORT_P_H
diff --git a/src/gui/util/qshadernodesloader.cpp b/src/gui/util/qshadernodesloader.cpp
new file mode 100644
index 0000000000..db34b6d44d
--- /dev/null
+++ b/src/gui/util/qshadernodesloader.cpp
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qshadernodesloader_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsondocument.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qmetaobject.h>
+
+QT_BEGIN_NAMESPACE
+
+QShaderNodesLoader::QShaderNodesLoader() Q_DECL_NOTHROW
+ : m_status(Null),
+ m_device(nullptr)
+{
+}
+
+QShaderNodesLoader::Status QShaderNodesLoader::status() const Q_DECL_NOTHROW
+{
+ return m_status;
+}
+
+QHash<QString, QShaderNode> QShaderNodesLoader::nodes() const Q_DECL_NOTHROW
+{
+ return m_nodes;
+}
+
+QIODevice *QShaderNodesLoader::device() const Q_DECL_NOTHROW
+{
+ return m_device;
+}
+
+void QShaderNodesLoader::setDevice(QIODevice *device) Q_DECL_NOTHROW
+{
+ m_device = device;
+ m_nodes.clear();
+ m_status = !m_device ? Null
+ : (m_device->openMode() & QIODevice::ReadOnly) ? Waiting
+ : Error;
+}
+
+void QShaderNodesLoader::load()
+{
+ if (m_status == Error)
+ return;
+
+ auto error = QJsonParseError();
+ const auto document = QJsonDocument::fromJson(m_device->readAll(), &error);
+
+ if (error.error != QJsonParseError::NoError) {
+ qWarning() << "Invalid JSON document:" << error.errorString();
+ m_status = Error;
+ return;
+ }
+
+ if (document.isEmpty() || !document.isObject()) {
+ qWarning() << "Invalid JSON document, root should be an object";
+ m_status = Error;
+ return;
+ }
+
+ const auto root = document.object();
+
+ bool hasError = false;
+
+ for (const auto &property : root.keys()) {
+ const auto nodeValue = root.value(property);
+ if (!nodeValue.isObject()) {
+ qWarning() << "Invalid node found";
+ hasError = true;
+ break;
+ }
+
+ const auto nodeObject = nodeValue.toObject();
+
+ auto node = QShaderNode();
+
+ const auto inputsValue = nodeObject.value(QStringLiteral("inputs"));
+ if (inputsValue.isArray()) {
+ const auto inputsArray = inputsValue.toArray();
+ for (const auto &inputValue : inputsArray) {
+ if (!inputValue.isString()) {
+ qWarning() << "Non-string value in inputs";
+ hasError = true;
+ break;
+ }
+
+ auto input = QShaderNodePort();
+ input.direction = QShaderNodePort::Input;
+ input.name = inputValue.toString();
+ node.addPort(input);
+ }
+ }
+
+ const auto outputsValue = nodeObject.value(QStringLiteral("outputs"));
+ if (outputsValue.isArray()) {
+ const auto outputsArray = outputsValue.toArray();
+ for (const auto &outputValue : outputsArray) {
+ if (!outputValue.isString()) {
+ qWarning() << "Non-string value in outputs";
+ hasError = true;
+ break;
+ }
+
+ auto output = QShaderNodePort();
+ output.direction = QShaderNodePort::Output;
+ output.name = outputValue.toString();
+ node.addPort(output);
+ }
+ }
+
+ const auto parametersValue = nodeObject.value(QStringLiteral("parameters"));
+ if (parametersValue.isObject()) {
+ const auto parametersObject = parametersValue.toObject();
+ for (const auto &parameterName : parametersObject.keys()) {
+ const auto parameterValue = parametersObject.value(parameterName);
+ if (parameterValue.isObject()) {
+ const auto parameterObject = parameterValue.toObject();
+ const auto type = parameterObject.value(QStringLiteral("type")).toString();
+ const auto typeId = QMetaType::type(type.toUtf8());
+
+ const auto value = parameterObject.value(QStringLiteral("value")).toString();
+ auto variant = QVariant(value);
+
+ if (QMetaType::typeFlags(typeId) & QMetaType::IsEnumeration) {
+ const auto metaObject = QMetaType::metaObjectForType(typeId);
+ const auto className = metaObject->className();
+ const auto enumName = type.mid(static_cast<int>(qstrlen(className)) + 2).toUtf8();
+ const auto metaEnum = metaObject->enumerator(metaObject->indexOfEnumerator(enumName));
+ const auto enumValue = metaEnum.keyToValue(value.toUtf8());
+ variant = QVariant(enumValue);
+ variant.convert(typeId);
+ } else {
+ variant.convert(typeId);
+ }
+ node.setParameter(parameterName, variant);
+ } else {
+ node.setParameter(parameterName, parameterValue.toVariant());
+ }
+ }
+ }
+
+ const auto rulesValue = nodeObject.value(QStringLiteral("rules"));
+ if (rulesValue.isArray()) {
+ const auto rulesArray = rulesValue.toArray();
+ for (const auto &ruleValue : rulesArray) {
+ if (!ruleValue.isObject()) {
+ qWarning() << "Rules should be objects";
+ hasError = true;
+ break;
+ }
+
+ const auto ruleObject = ruleValue.toObject();
+
+ const auto formatValue = ruleObject.value(QStringLiteral("format"));
+ if (!formatValue.isObject()) {
+ qWarning() << "Format is mandatory in rules and should be an object";
+ hasError = true;
+ break;
+ }
+
+ const auto formatObject = formatValue.toObject();
+ auto format = QShaderFormat();
+
+ const auto apiValue = formatObject.value(QStringLiteral("api"));
+ if (!apiValue.isString()) {
+ qWarning() << "Format API must be a string";
+ hasError = true;
+ break;
+ }
+
+ const auto api = apiValue.toString();
+ format.setApi(api == QStringLiteral("OpenGLES") ? QShaderFormat::OpenGLES
+ : api == QStringLiteral("OpenGLNoProfile") ? QShaderFormat::OpenGLNoProfile
+ : api == QStringLiteral("OpenGLCoreProfile") ? QShaderFormat::OpenGLCoreProfile
+ : api == QStringLiteral("OpenGLCompatibilityProfile") ? QShaderFormat::OpenGLCompatibilityProfile
+ : QShaderFormat::NoApi);
+ if (format.api() == QShaderFormat::NoApi) {
+ qWarning() << "Format API must be one of: OpenGLES, OpenGLNoProfile, OpenGLCoreProfile or OpenGLCompatibilityProfile";
+ hasError = true;
+ break;
+ }
+
+ const auto majorValue = formatObject.value(QStringLiteral("major"));
+ const auto minorValue = formatObject.value(QStringLiteral("minor"));
+ if (!majorValue.isDouble() || !minorValue.isDouble()) {
+ qWarning() << "Format major and minor version must be values";
+ hasError = true;
+ break;
+ }
+ format.setVersion(QVersionNumber(majorValue.toInt(), minorValue.toInt()));
+
+ const auto extensionsValue = formatObject.value(QStringLiteral("extensions"));
+ const auto extensionsArray = extensionsValue.toArray();
+ auto extensions = QStringList();
+ std::transform(extensionsArray.constBegin(), extensionsArray.constEnd(),
+ std::back_inserter(extensions),
+ [] (const QJsonValue &extensionValue) { return extensionValue.toString(); });
+ format.setExtensions(extensions);
+
+ const auto vendor = formatObject.value(QStringLiteral("vendor")).toString();
+ format.setVendor(vendor);
+
+ const auto substitutionValue = ruleObject.value(QStringLiteral("substitution"));
+ if (!substitutionValue.isString()) {
+ qWarning() << "Substitution needs to be a string";
+ hasError = true;
+ break;
+ }
+
+ const auto substitution = substitutionValue.toString().toUtf8();
+
+ const auto snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));
+ const auto snippetsArray = snippetsValue.toArray();
+ auto snippets = QByteArrayList();
+ std::transform(snippetsArray.constBegin(), snippetsArray.constEnd(),
+ std::back_inserter(snippets),
+ [] (const QJsonValue &snippetValue) { return snippetValue.toString().toUtf8(); });
+
+ node.addRule(format, QShaderNode::Rule(substitution, snippets));
+ }
+ }
+
+ m_nodes.insert(property, node);
+ }
+
+ if (hasError) {
+ m_status = Error;
+ m_nodes.clear();
+ } else {
+ m_status = Ready;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/util/qshadernodesloader_p.h b/src/gui/util/qshadernodesloader_p.h
new file mode 100644
index 0000000000..2696e958b6
--- /dev/null
+++ b/src/gui/util/qshadernodesloader_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHADERNODESLOADER_P_H
+#define QSHADERNODESLOADER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/private/qtguiglobal_p.h>
+
+#include <QtGui/private/qshadergraph_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class QShaderNodesLoader
+{
+public:
+ enum Status : char {
+ Null,
+ Waiting,
+ Ready,
+ Error
+ };
+
+ Q_GUI_EXPORT QShaderNodesLoader() Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT Status status() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT QHash<QString, QShaderNode> nodes() const Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT QIODevice *device() const Q_DECL_NOTHROW;
+ Q_GUI_EXPORT void setDevice(QIODevice *device) Q_DECL_NOTHROW;
+
+ Q_GUI_EXPORT void load();
+
+private:
+ Status m_status;
+ QIODevice *m_device;
+ QHash<QString, QShaderNode> m_nodes;
+};
+
+Q_DECLARE_TYPEINFO(QShaderNodesLoader, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QShaderNodesLoader)
+Q_DECLARE_METATYPE(QShaderNodesLoader::Status)
+
+#endif // QSHADERNODESLOADER_P_H
diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp
index fb9dfc9f69..1709012291 100644
--- a/src/gui/util/qvalidator.cpp
+++ b/src/gui/util/qvalidator.cpp
@@ -420,9 +420,9 @@ QValidator::State QIntValidator::validate(QString & input, int&) const
if (buff.size() == 1 && (buff.at(0) == '+' || buff.at(0) == '-'))
return Intermediate;
- bool ok, overflow;
- qlonglong entered = QLocaleData::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow);
- if (overflow || !ok)
+ bool ok;
+ qlonglong entered = QLocaleData::bytearrayToLongLong(buff.constData(), 10, &ok);
+ if (!ok)
return Invalid;
if (entered >= b && entered <= t) {
@@ -447,9 +447,9 @@ void QIntValidator::fixup(QString &input) const
locale().numberOptions())) {
return;
}
- bool ok, overflow;
- qlonglong entered = QLocaleData::bytearrayToLongLong(buff.constData(), 10, &ok, &overflow);
- if (ok && !overflow)
+ bool ok;
+ qlonglong entered = QLocaleData::bytearrayToLongLong(buff.constData(), 10, &ok);
+ if (ok)
input = locale().toString(entered);
}
diff --git a/src/gui/util/util.pri b/src/gui/util/util.pri
index 79c83599b9..cf3cbee48e 100644
--- a/src/gui/util/util.pri
+++ b/src/gui/util/util.pri
@@ -6,11 +6,27 @@ HEADERS += \
util/qvalidator.h \
util/qgridlayoutengine_p.h \
util/qabstractlayoutstyleinfo_p.h \
- util/qlayoutpolicy_p.h
+ util/qlayoutpolicy_p.h \
+ util/qshaderformat_p.h \
+ util/qshadergenerator_p.h \
+ util/qshadergraph_p.h \
+ util/qshadergraphloader_p.h \
+ util/qshaderlanguage_p.h \
+ util/qshadernode_p.h \
+ util/qshadernodeport_p.h \
+ util/qshadernodesloader_p.h
SOURCES += \
util/qdesktopservices.cpp \
util/qvalidator.cpp \
util/qgridlayoutengine.cpp \
util/qabstractlayoutstyleinfo.cpp \
- util/qlayoutpolicy.cpp
+ util/qlayoutpolicy.cpp \
+ util/qshaderformat.cpp \
+ util/qshadergenerator.cpp \
+ util/qshadergraph.cpp \
+ util/qshadergraphloader.cpp \
+ util/qshaderlanguage.cpp \
+ util/qshadernode.cpp \
+ util/qshadernodeport.cpp \
+ util/qshadernodesloader.cpp
diff --git a/src/gui/vulkan/KHRONOS_LICENSE.txt b/src/gui/vulkan/KHRONOS_LICENSE.txt
new file mode 100644
index 0000000000..7f6672d50e
--- /dev/null
+++ b/src/gui/vulkan/KHRONOS_LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2015-2017 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and/or associated documentation files (the
+"Materials"), to deal in the Materials without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Materials, and to
+permit persons to whom the Materials are furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/src/gui/vulkan/qplatformvulkaninstance.cpp b/src/gui/vulkan/qplatformvulkaninstance.cpp
new file mode 100644
index 0000000000..6201d3ec11
--- /dev/null
+++ b/src/gui/vulkan/qplatformvulkaninstance.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformvulkaninstance.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPlatformVulkanInstance
+ \since 5.10
+ \internal
+ \preliminary
+ \ingroup qpa
+
+ \brief The QPlatformVulkanInstance class provides an abstraction for Vulkan instances.
+
+ The platform Vulkan instance is responsible for loading a Vulkan library,
+ resolving the basic entry points for creating instances, providing support
+ for creating new or adopting existing VkInstances, and abstracting some
+ WSI-specifics like checking if a given queue family can be used to present
+ using a given window.
+
+ \note platform plugins will typically subclass not this class, but rather
+ QBasicVulkanPlatformInstance.
+
+ \note Vulkan instance creation is split into two phases: a new
+ QPlatformVulkanInstance is expected to load the Vulkan library and do basic
+ initialization, after which the supported layers and extensions can be
+ queried. Everything else is deferred into createOrAdoptInstance().
+*/
+
+class QPlatformVulkanInstancePrivate
+{
+public:
+ QPlatformVulkanInstancePrivate() { }
+};
+
+QPlatformVulkanInstance::QPlatformVulkanInstance()
+ : d_ptr(new QPlatformVulkanInstancePrivate)
+{
+}
+
+QPlatformVulkanInstance::~QPlatformVulkanInstance()
+{
+}
+
+void QPlatformVulkanInstance::presentQueued(QWindow *window)
+{
+ Q_UNUSED(window);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/vulkan/qplatformvulkaninstance.h b/src/gui/vulkan/qplatformvulkaninstance.h
new file mode 100644
index 0000000000..9470e2d0b4
--- /dev/null
+++ b/src/gui/vulkan/qplatformvulkaninstance.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMVULKANINSTANCE_H
+#define QPLATFORMVULKANINSTANCE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is part of the QPA API and is not meant to be used
+// in applications. Usage of this API may make your code
+// source and binary incompatible with future versions of Qt.
+//
+
+#include <QtGui/qtguiglobal.h>
+
+#if QT_CONFIG(vulkan) || defined(Q_CLANG_QDOC)
+
+#include <qvulkaninstance.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformVulkanInstancePrivate;
+
+class Q_GUI_EXPORT QPlatformVulkanInstance
+{
+ Q_DECLARE_PRIVATE(QPlatformVulkanInstance)
+
+public:
+ QPlatformVulkanInstance();
+ virtual ~QPlatformVulkanInstance();
+
+ virtual QVulkanInfoVector<QVulkanLayer> supportedLayers() const = 0;
+ virtual QVulkanInfoVector<QVulkanExtension> supportedExtensions() const = 0;
+ virtual void createOrAdoptInstance() = 0;
+ virtual bool isValid() const = 0;
+ virtual VkResult errorCode() const = 0;
+ virtual VkInstance vkInstance() const = 0;
+ virtual QByteArrayList enabledLayers() const = 0;
+ virtual QByteArrayList enabledExtensions() const = 0;
+ virtual PFN_vkVoidFunction getInstanceProcAddr(const char *name) = 0;
+ virtual bool supportsPresent(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, QWindow *window) = 0;
+ virtual void presentQueued(QWindow *window);
+
+private:
+ QScopedPointer<QPlatformVulkanInstancePrivate> d_ptr;
+ Q_DISABLE_COPY(QPlatformVulkanInstance)
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_CONFIG(vulkan)
+
+#endif // QPLATFORMVULKANINSTANCE_H
diff --git a/src/gui/vulkan/qt_attribution.json b/src/gui/vulkan/qt_attribution.json
new file mode 100644
index 0000000000..3c09e9f498
--- /dev/null
+++ b/src/gui/vulkan/qt_attribution.json
@@ -0,0 +1,17 @@
+[
+ {
+ "Id": "vulkan-xml-spec",
+ "Name": "Vulkan API Registry",
+ "QDocModule": "qtgui",
+ "Description": "Vulkan XML API Registry.",
+ "QtUsage": "Used to dynamically generate the sources for the QVulkan(Device)Functions classes.",
+ "Path": "vk.xml",
+
+ "Homepage": "https://www.khronos.org/",
+ "Version": "1.0.39",
+ "License": "MIT License",
+ "LicenseId": "MIT",
+ "LicenseFile": "KHRONOS_LICENSE.txt",
+ "Copyright": "Copyright (c) 2015-2017 The Khronos Group Inc."
+ }
+]
diff --git a/src/gui/vulkan/qvulkanfunctions.cpp b/src/gui/vulkan/qvulkanfunctions.cpp
new file mode 100644
index 0000000000..c5f9616d20
--- /dev/null
+++ b/src/gui/vulkan/qvulkanfunctions.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/qvulkanfunctions_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QVulkanFunctions
+ \since 5.10
+ \ingroup painting-3D
+ \inmodule QtGui
+ \wrapper
+
+ \brief The QVulkanFunctions class provides cross-platform access to the
+ instance level core Vulkan 1.0 API.
+
+ Qt and Qt applications do not link to any Vulkan libraries by default.
+ Instead, all functions are resolved dynamically at run time. Each
+ QVulkanInstance provides a QVulkanFunctions object retrievable via
+ QVulkanInstance::functions(). This does not contain device level functions
+ in order to avoid the potential overhead of an internal dispatching.
+ Instead, functions that rely on a device, or a dispatchable child object of
+ a device, are exposed via QVulkanDeviceFunctions and
+ QVulkanInstance::deviceFunctions(). QVulkanFunctions and
+ QVulkanDeviceFunctions together provides access to the full core Vulkan
+ API, excluding any extensions.
+
+ \note QVulkanFunctions instances cannot be constructed directly.
+
+ The typical usage is the following:
+
+ \code
+ void Window::render()
+ {
+ QVulkanInstance *inst = vulkanInstance();
+ QVulkanFunctions *f = inst->functions();
+ ...
+ VkResult err = f->vkAllocateCommandBuffers(device, &cmdBufInfo, &cmdBuf);
+ ...
+ }
+ \endcode
+
+ \note Windowing system interface (WSI) specifics and extensions are
+ excluded. This class only covers core Vulkan commands, with the exception
+ of instance creation, destruction, and function resolving, since such
+ functionality is covered by QVulkanInstance itself.
+
+ To access additional functions, applications can use
+ QVulkanInstance::getInstanceProcAddr() and vkGetDeviceProcAddr().
+ Applications can also decide to link to a Vulkan library directly, as
+ platforms with an appropriate loader will typically export function symbols
+ for the core commands. See
+ \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html}{the
+ man page for vkGetInstanceProcAddr} for more information.
+
+ \sa QVulkanInstance, QVulkanDeviceFunctions, QWindow::setVulkanInstance(), QWindow::setSurfaceType()
+*/
+
+/*!
+ \class QVulkanDeviceFunctions
+ \since 5.10
+ \ingroup painting-3D
+ \inmodule QtGui
+ \wrapper
+
+ \brief The QVulkanDeviceFunctions class provides cross-platform access to
+ the device level core Vulkan 1.0 API.
+
+ Qt and Qt applications do not link to any Vulkan libraries by default.
+ Instead, all functions are resolved dynamically at run time. Each
+ QVulkanInstance provides a QVulkanFunctions object retrievable via
+ QVulkanInstance::functions(). This does not contain device level functions
+ in order to avoid the potential overhead of an internal dispatching.
+ Instead, functions that rely on a device, or a dispatchable child object of
+ a device, are exposed via QVulkanDeviceFunctions and
+ QVulkanInstance::deviceFunctions(). QVulkanFunctions and
+ QVulkanDeviceFunctions together provides access to the full core Vulkan
+ API, excluding any extensions.
+
+ \note QVulkanDeviceFunctions instances cannot be constructed directly.
+
+ The typical usage is the following:
+
+ \code
+ void Window::render()
+ {
+ QVulkanInstance *inst = vulkanInstance();
+ QVulkanDeviceFunctions *df = inst->deviceFunctions(device);
+ VkResult err = df->vkAllocateCommandBuffers(device, &cmdBufInfo, &cmdBuf);
+ ...
+ }
+ \endcode
+
+ The QVulkanDeviceFunctions object specific to the provided VkDevice is
+ created when QVulkanInstance::deviceFunctions() is first called with the
+ device in question. The object is then cached internally.
+
+ To access additional functions, applications can use
+ QVulkanInstance::getInstanceProcAddr() and vkGetDeviceProcAddr().
+ Applications can also decide to link to a Vulkan library directly, as many
+ implementations export function symbols for the core commands. See
+ \l{https://www.khronos.org/registry/vulkan/specs/1.0/man/html/vkGetInstanceProcAddr.html}{the
+ man page for vkGetInstanceProcAddr} for more information.
+
+ \sa QVulkanInstance, QVulkanFunctions, QWindow::setVulkanInstance(), QWindow::setSurfaceType()
+*/
+
+/*
+ Constructs a new QVulkanFunctions for \a inst.
+ \internal
+ */
+QVulkanFunctions::QVulkanFunctions(QVulkanInstance *inst)
+ : d_ptr(new QVulkanFunctionsPrivate(inst))
+{
+}
+
+/*
+ Destructor.
+ */
+QVulkanFunctions::~QVulkanFunctions()
+{
+}
+
+/*
+ Constructs a new QVulkanDeviceFunctions for \a inst and the given \a device.
+ \internal
+ */
+QVulkanDeviceFunctions::QVulkanDeviceFunctions(QVulkanInstance *inst, VkDevice device)
+ : d_ptr(new QVulkanDeviceFunctionsPrivate(inst, device))
+{
+}
+
+/*
+ Destructor.
+ */
+QVulkanDeviceFunctions::~QVulkanDeviceFunctions()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/vulkan/qvulkaninstance.cpp b/src/gui/vulkan/qvulkaninstance.cpp
new file mode 100644
index 0000000000..2e03be8151
--- /dev/null
+++ b/src/gui/vulkan/qvulkaninstance.cpp
@@ -0,0 +1,894 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qvulkaninstance.h"
+#include <private/qvulkanfunctions_p.h>
+#include <qpa/qplatformvulkaninstance.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QVulkanInstance
+ \since 5.10
+ \inmodule QtGui
+
+ \brief The QVulkanInstance class represents a native Vulkan instance, enabling
+ Vulkan rendering onto a QSurface.
+
+ \l{https://www.khronos.org/vulkan/}{Vulkan} is a cross-platform, explicit
+ graphics and compute API. This class provides support for loading a Vulkan
+ library and creating an \c instance in a cross-platform manner. For an
+ introduction on Vulkan instances, refer
+ \l{https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#initialization-instances}{to
+ section 3.2 of the specification}.
+
+ \note Platform-specific support for Vulkan instances and windows with
+ Vulkan-capable surfaces is provided by the various platform plugins. Not
+ all of them will support Vulkan, however. When running on such a platform,
+ create() will fail and always return \c false.
+
+ \note Vulkan support may get automatically disabled for a given Qt build due
+ to not having the necessary Vulkan headers available at build time. When
+ this is the case, and the output of \c configure indicates Vulkan support is
+ disabled, the QVulkan* classes will be unavailable.
+
+ \note Some functions changed their signature between the various Vulkan
+ header revisions. When building Qt and only headers with the old,
+ conflicting signatures are present in a system, Vulkan support will get
+ disabled. It is recommended to use headers from Vulkan 1.0.39 or newer.
+
+ \section1 Initialization
+
+ Similarly to QOpenGLContext, any actual Vulkan instance creation happens
+ only when calling create(). This allows using QVulkanInstance as a plain
+ member variable while retaining control over when to perform
+ initialization.
+
+ Querying the supported instance-level layers and extensions is possible by
+ calling supportedLayers() and supportedExtensions(). These ensure the
+ Vulkan library is loaded, and can therefore be called safely before
+ create() as well.
+
+ Instances store per-application Vulkan state and creating a \c VkInstance
+ object initializes the Vulkan library. In practice there will typically be
+ a single instance constructed early on in main(). The object then stays
+ alive until exiting the application.
+
+ Every Vulkan-based QWindow must be associated with a QVulkanInstance by
+ calling QWindow::setVulkanInstance(). Thus a typical application pattern is
+ the following:
+
+ \code
+ int main(int argc, char **argv)
+ {
+ QGuiApplication app(argc, argv);
+
+ QVulkanInstance inst;
+ if (!inst.create())
+ return 1;
+
+ ...
+ window->setVulkanInstance(&inst);
+ window->show();
+
+ return app.exec();
+ }
+ \endcode
+
+ \section1 Configuration
+
+ QVulkanInstance automatically enables the minimum set of extensions it
+ needs on the newly created instance. In practice this means the
+ \c{VK_KHR_*_surface} family of extensions.
+
+ By default Vulkan debug output, for example messages from the validation
+ layers, is routed to qDebug(). This can be disabled by passing the flag
+ \c NoDebugOutputRedirect to setFlags() \e before invoking create().
+
+ To enable additional layers and extensions, provide the list via
+ setLayers() and setExtensions() \e before invoking create(). When a
+ given layer or extension is not reported as available from the instance,
+ the request is ignored. After a successful call to create(), the values
+ returned from functions like layers() and extensions() reflect the actual
+ enabled layers and extensions. When necessary, for example to avoid
+ requesting extensions that conflict and thus would fail the Vulkan instance
+ creation, the list of actually supported layers and extensions can be
+ examined via supportedLayers() and supportedExtensions() before calling
+ create().
+
+ For example, to enable the standard validation layers, one could do the
+ following:
+
+ \code
+ QVulkanInstance inst;
+
+ // Enable validation layer, if supported. Messages go to qDebug by default.
+ inst.setLayers(QByteArrayList() << "VK_LAYER_LUNARG_standard_validation");
+
+ bool ok = inst.create();
+ if (!ok)
+ ... // Vulkan not available
+ if (!inst.layers().contains("VK_LAYER_LUNARG_standard_validation"))
+ ... // validation layer not available
+ \endcode
+
+ Or, alternatively, to make decisions before attempting to create a Vulkan
+ instance:
+
+ \code
+ QVulkanInstance inst;
+
+ if (inst.supportedLayers().contains("VK_LAYER_LUNARG_standard_validation"))
+ ...
+
+ bool ok = inst.create();
+ ...
+ \endcode
+
+ \section1 Adopting an Existing Instance
+
+ By default QVulkanInstance creates a new Vulkan instance. When working with
+ external engines and renderers, this may sometimes not be desirable. When
+ there is a \c VkInstance handle already available, call setVkInstance()
+ before invoking create(). This way no additional instances will get
+ created, and QVulkanInstance will not own the handle.
+
+ \note It is up to the component creating the external instance to ensure
+ the necessary extensions are enabled on it. These are: \c{VK_KHR_surface},
+ the WSI-specific \c{VK_KHR_*_surface} that is appropriate for the platform
+ in question, and \c{VK_EXT_debug_report} in case QVulkanInstance's debug
+ output redirection is desired.
+
+ \section1 Accessing Core Vulkan Commands
+
+ To access the \c VkInstance handle the QVulkanInstance wraps, call
+ vkInstance(). To resolve Vulkan functions, call getInstanceProcAddr(). For
+ core Vulkan commands manual resolving is not necessary as they are provided
+ via the QVulkanFunctions and QVulkanDeviceFunctions objects accessible via
+ functions() and deviceFunctions().
+
+ \note QVulkanFunctions and QVulkanDeviceFunctions are generated from the
+ Vulkan API XML specifications when building the Qt libraries. Therefore no
+ documentation is provided for them. They contain the Vulkan 1.0 functions
+ with the same signatures as described in the
+ \l{https://www.khronos.org/registry/vulkan/specs/1.0/html/}{Vulkan API
+ documentation}.
+
+ \section1 Getting a Native Vulkan Surface for a Window
+
+ The two common windowing system specific operations are getting a surface
+ (a \c{VkSurfaceKHR} handle) for a window, and querying if a given queue
+ family supports presenting to a given surface. To avoid WSI-specific bits
+ in the applications, these are abstracted by QVulkanInstance and the
+ underlying QPA layers.
+
+ To create a Vulkan surface for a window, or retrieve an existing one,
+ call surfaceForWindow(). Most platforms will only create the surface via
+ \c{VK_KHR_*_surface} when first calling surfaceForWindow(), but there may be
+ platform-specific variations in the internal behavior. Once created,
+ subsequent calls to surfaceForWindow() just return the same handle. This
+ fits the structure of typical Vulkan-enabled QWindow subclasses well.
+
+ To query if a given queue family within a physical device can be used to
+ perform presentation to a given surface, call supportsPresent(). This
+ encapsulates both the generic \c vkGetPhysicalDeviceSurfaceSupportKHR and
+ the WSI-specific \c{vkGetPhysicalDevice*PresentationSupportKHR} checks.
+
+ \section1 Troubleshooting
+
+ Besides returning \c false from create() or \c 0 from surfaceForWindow(),
+ critical errors will also get printed to the debug output via qWarning().
+ Additional logging can be requested by enabling debug output for the
+ logging category \c{qt.vulkan}. The actual Vulkan error code from instance
+ creation can be retrieved by calling errorCode() after a failing create().
+
+ In some special cases it may be necessary to override the Vulkan
+ library name. This can be achieved by setting the \c{QT_VULKAN_LIB}
+ environment variable.
+
+ \section1 Example
+
+ The following is the basic outline of creating a Vulkan-capable QWindow:
+
+ \code
+ class VulkanWindow : public QWindow
+ {
+ public:
+ VulkanWindow() {
+ setSurfaceType(VulkanSurface);
+ }
+
+ void exposeEvent(QExposeEvent *) {
+ if (isExposed()) {
+ if (!m_initialized) {
+ m_initialized = true;
+ // initialize device, swapchain, etc.
+ QVulkanInstance *inst = vulkanInstance();
+ QVulkanFunctions *f = inst->functions();
+ uint32_t devCount = 0;
+ f->vkEnumeratePhysicalDevices(inst->vkInstance(), &devCount, nullptr);
+ ...
+ // build the first frame
+ render();
+ }
+ }
+ }
+
+ bool event(QEvent *e) {
+ if (e->type == QEvent::UpdateRequest)
+ render();
+ return QWindow::event(e);
+ }
+
+ void render() {
+ ...
+ requestUpdate(); // render continuously
+ }
+
+ private:
+ bool m_initialized = false;
+ };
+
+ int main(int argc, char **argv)
+ {
+ QGuiApplication app(argc, argv);
+
+ QVulkanInstance inst;
+ if (!inst.create()) {
+ qWarning("Vulkan not available");
+ return 1;
+ }
+
+ VulkanWindow window;
+ window.showMaximized();
+
+ return app.exec();
+
+ }
+ \endcode
+
+ \note In addition to expose, a well-behaving window implementation will
+ also have to take care of additional events like resize and
+ QPlatformSurfaceEvent in order to ensure proper management of the
+ swap chain. Additionally, some platforms may require releasing resources
+ when not being exposed anymore.
+
+ \section1 Using C++ Bindings for Vulkan
+
+ Combining Qt's Vulkan enablers with a C++ Vulkan wrapper, for example
+ \l{https://github.com/KhronosGroup/Vulkan-Hpp}{Vulkan-Hpp}, is possible as
+ well. The pre-requisite here is that the C++ layer must be able to adopt
+ native handles (VkInstance, VkSurfaceKHR) in its classes without taking
+ ownership (since the ownership stays with QVulkanInstance and QWindow).
+ Consider also the following:
+
+ \list
+
+ \li Some wrappers require exception support to be enabled. Qt does not use
+ exceptions. To enable exceptions for the application, add \c{CONFIG += exceptions}
+ to the \c{.pro} file.
+
+ \li Some wrappers call Vulkan functions directly, assuming \c{vulkan.h}
+ provides prototypes and the application links to a Vulkan library exporting
+ all necessary symbols. Qt may not directly link to a Vulkan library.
+ Therefore, on some platforms it may be necessary to add
+ \c{LIBS += -lvulkan} or similar in the application's \c{.pro} file.
+
+ \li The headers for the QVulkan classes may include \c{vulkan.h} with
+ \c{VK_NO_PROTOTYPES} enabled. This can cause issues in C++ wrapper headers
+ that rely on the prototypes. Hence in application code it may be
+ necessary to include \c{vulkan.hpp} or similar before any of the QVulkan
+ headers.
+
+ \endlist
+
+ \sa QVulkanFunctions, QSurface::SurfaceType
+*/
+
+/*!
+ \enum QVulkanInstance::Flag
+ \since 5.10
+
+ This enum describes the flags that can be passed to setFlags(). These control
+ the behavior of create().
+
+ \value NoDebugOutputRedirect Disables Vulkan debug output (\c{VK_EXT_debug_report}) redirection to qDebug.
+*/
+
+class QVulkanInstancePrivate
+{
+public:
+ QVulkanInstancePrivate(QVulkanInstance *q)
+ : q_ptr(q),
+ vkInst(VK_NULL_HANDLE),
+ flags(0),
+ errorCode(VK_SUCCESS)
+ { }
+ ~QVulkanInstancePrivate() { reset(); }
+
+ bool ensureVulkan();
+ void reset();
+
+ QVulkanInstance *q_ptr;
+ QScopedPointer<QPlatformVulkanInstance> platformInst;
+ VkInstance vkInst;
+ QVulkanInstance::Flags flags;
+ QByteArrayList layers;
+ QByteArrayList extensions;
+ QVersionNumber apiVersion;
+ VkResult errorCode;
+ QScopedPointer<QVulkanFunctions> funcs;
+ QHash<VkDevice, QVulkanDeviceFunctions *> deviceFuncs;
+};
+
+bool QVulkanInstancePrivate::ensureVulkan()
+{
+ if (!platformInst) {
+ platformInst.reset(QGuiApplicationPrivate::platformIntegration()->createPlatformVulkanInstance(q_ptr));
+ if (!platformInst) {
+ qWarning("QVulkanInstance: Failed to initialize Vulkan");
+ return false;
+ }
+ }
+ return true;
+}
+
+void QVulkanInstancePrivate::reset()
+{
+ qDeleteAll(deviceFuncs);
+ deviceFuncs.clear();
+ funcs.reset();
+ platformInst.reset();
+ vkInst = VK_NULL_HANDLE;
+ errorCode = VK_SUCCESS;
+}
+
+/*!
+ Constructs a new instance.
+
+ \note No Vulkan initialization is performed in the constructor.