Merge remote-tracking branch 'origin/5.12' into 5.13

Conflicts:
	src/corelib/tools/qlocale.qdoc
	tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp

Done-with: Edward Welbourne <edward.welbourne@qt.io>
Done-with: Volker Hilsheimer <volker.hilsheimer@qt.io>
Change-Id: I88e0757b2d020f0a244714c87844631df4b3fd13
This commit is contained in:
Liang Qi 2019-04-16 09:34:50 +02:00
commit 9d67bf6e96
38 changed files with 628 additions and 243 deletions

View File

@ -26,20 +26,29 @@ contains(CMAKE_INSTALL_LIBS_DIR, ^(/usr)?/lib(64)?.*): CMAKE_USR_MOVE_WORKAROUND
CMAKE_OUT_DIR = $$MODULE_BASE_OUTDIR/lib/cmake
# Core, Network, an external module named Foo
CMAKE_MODULE_NAME = $$cmakeModuleName($${MODULE})
# QtCore, QtNetwork, still Foo
CMAKE_INCLUDE_NAME = $$eval(QT.$${MODULE}.name)
# TARGET here is the one changed at the end of qt_module.prf,
# which already contains the Qt5 prefix and QT_LIBINFIX suffix :
# Qt5Core_suffix, Qt5Network_suffix, Foo_suffix
# (or QtCore_suffix, Foo_suffix on macos with -framework)
CMAKE_QT_STEM = $${TARGET}
!generated_privates {
isEmpty(SYNCQT.INJECTED_PRIVATE_HEADER_FILES):isEmpty(SYNCQT.PRIVATE_HEADER_FILES): \
CMAKE_NO_PRIVATE_INCLUDES = true
}
split_incpath {
CMAKE_ADD_SOURCE_INCLUDE_DIRS = true
CMAKE_SOURCE_INCLUDES = \
$$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME})
$$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE $$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME})
CMAKE_SOURCE_PRIVATE_INCLUDES = \
$$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION) \
$$QT_MODULE_INCLUDE_BASE/Qt$${CMAKE_MODULE_NAME}/$$eval(QT.$${MODULE}.VERSION)/Qt$${CMAKE_MODULE_NAME})
$$cmakeTargetPaths($$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME}/$$eval(QT.$${MODULE}.VERSION) \
$$QT_MODULE_INCLUDE_BASE/$${CMAKE_INCLUDE_NAME}/$$eval(QT.$${MODULE}.VERSION)/$${CMAKE_INCLUDE_NAME})
cmake_extra_source_includes.input = $$PWD/data/cmake/ExtraSourceIncludes.cmake.in
cmake_extra_source_includes.output = $$CMAKE_OUT_DIR/Qt5$${CMAKE_MODULE_NAME}/ExtraSourceIncludes.cmake
@ -200,10 +209,6 @@ CMAKE_QT5_MODULE_DEPS = $$join(lib_deps, ";")
CMAKE_INTERFACE_MODULE_DEPS = $$join(aux_mod_deps, ";")
CMAKE_INTERFACE_QT5_MODULE_DEPS = $$join(aux_lib_deps, ";")
# TARGET here is the one changed at the end of qt_module.prf,
# which already contains the Qt5 prefix and QT_LIBINFIX suffix
CMAKE_QT_STEM = $${TARGET}
mac {
!isEmpty(CMAKE_STATIC_TYPE) {
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.a
@ -213,8 +218,8 @@ mac {
CMAKE_PRL_FILE_LOCATION_RELEASE = lib$${CMAKE_QT_STEM}.prl
} else {
qt_framework {
CMAKE_LIB_FILE_LOCATION_DEBUG = Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}.framework/Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}
CMAKE_LIB_FILE_LOCATION_RELEASE = Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}.framework/Qt$${CMAKE_MODULE_NAME}$${QT_LIBINFIX}
CMAKE_LIB_FILE_LOCATION_DEBUG = $${CMAKE_QT_STEM}.framework/$${CMAKE_QT_STEM}
CMAKE_LIB_FILE_LOCATION_RELEASE = $${CMAKE_QT_STEM}.framework/$${CMAKE_QT_STEM}
CMAKE_BUILD_IS_FRAMEWORK = "true"
} else {
CMAKE_LIB_FILE_LOCATION_DEBUG = lib$${CMAKE_QT_STEM}_debug.$$eval(QT.$${MODULE}.VERSION).dylib

View File

@ -157,13 +157,13 @@ if (NOT TARGET Qt5::$${CMAKE_MODULE_NAME})
!!IF !no_module_headers
!!IF !isEmpty(CMAKE_BUILD_IS_FRAMEWORK)
set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Headers\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Headers\"
)
!!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES)
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}Qt$${CMAKE_MODULE_NAME}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/$${MODULE_INCNAME}\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/\"
\"${_qt5$${CMAKE_MODULE_NAME}_install_prefix}/$${CMAKE_LIB_DIR}$${CMAKE_QT_STEM}.framework/Versions/$$section(VERSION, ., 0, 0)/Headers/$$VERSION/$${MODULE_INCNAME}\"
)
!!ELSE
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\")
@ -180,7 +180,7 @@ if (NOT TARGET Qt5::$${CMAKE_MODULE_NAME})
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS \"\")
!!ENDIF
!!ELSE
set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS \"$$CMAKE_INCLUDE_DIR\" \"$${CMAKE_INCLUDE_DIR}Qt$${CMAKE_MODULE_NAME}\")
set(_Qt5$${CMAKE_MODULE_NAME}_OWN_INCLUDE_DIRS \"$$CMAKE_INCLUDE_DIR\" \"$${CMAKE_INCLUDE_DIR}$${CMAKE_INCLUDE_NAME}\")
!!IF isEmpty(CMAKE_NO_PRIVATE_INCLUDES)
set(Qt5$${CMAKE_MODULE_NAME}_PRIVATE_INCLUDE_DIRS
\"$${CMAKE_INCLUDE_DIR}$${MODULE_INCNAME}/$$VERSION\"

View File

@ -145,14 +145,16 @@ import_plugins:qtConfig(static) {
# the plugin path. Unknown plugins must rely on the default link path.
plug_type = $$eval(QT_PLUGIN.$${plug}.TYPE)
!isEmpty(plug_type) {
plug_name = $$QMAKE_PREFIX_STATICLIB$${plug}$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB
plug_path = $$eval(QT_PLUGIN.$${plug}.PATH)
isEmpty(plug_path): \
plug_path = $$[QT_INSTALL_PLUGINS/get]
LIBS += -L$$plug_path/$$plug_type
}
LIBS += $$plug_path/$$plug_type/$$plug_name
} else {
LIBS += -l$${plug}$$qtPlatformTargetSuffix()
}
}
}
# target variable, flag source variable
defineTest(qtProcessModuleFlags) {
@ -195,8 +197,6 @@ for(ever) {
qtProcessModuleFlags(DEFINES, QT.$${QTLIB}.DEFINES)
MODULE_INCLUDES -= $$QMAKE_DEFAULT_INCDIRS
MODULE_LIBS_ADD = $$MODULE_LIBS
MODULE_LIBS_ADD -= $$QMAKE_DEFAULT_LIBDIRS
# Frameworks shouldn't need include paths, but much code does not use
# module-qualified #includes, so by default we add paths which point
@ -209,23 +209,17 @@ for(ever) {
!isEmpty(MODULE_MODULE) {
contains(MODULE_CONFIG, lib_bundle) {
framework = $$MODULE_MODULE
# Linking frameworks by absolute path does not work.
LIBS$$var_sfx += -framework $$framework
} else {
!isEmpty(MODULE_LIBS_ADD): \
LIBS$$var_sfx += -L$$MODULE_LIBS_ADD
lib = $$MODULE_MODULE$$qtPlatformTargetSuffix()
LIBS$$var_sfx += -l$$lib
contains(MODULE_CONFIG, staticlib): \
PRE_TARGETDEPS *= $$MODULE_LIBS/$${QMAKE_PREFIX_STATICLIB}$${lib}.$${QMAKE_EXTENSION_STATICLIB}
!isEmpty(QMAKE_LSB) {
!isEmpty(MODULE_LIBS_ADD): \
QMAKE_LFLAGS *= --lsb-libpath=$$MODULE_LIBS_ADD
QMAKE_LFLAGS *= --lsb-shared-libs=$$lib
QMAKE_LIBDIR *= /opt/lsb/lib
win32|contains(MODULE_CONFIG, staticlib) {
lib = $$MODULE_LIBS/$$QMAKE_PREFIX_STATICLIB$${lib}.$$QMAKE_EXTENSION_STATICLIB
PRE_TARGETDEPS += $$lib
} else {
lib = $$MODULE_LIBS/$$QMAKE_PREFIX_SHLIB$${lib}.$$QMAKE_EXTENSION_SHLIB
}
LIBS$$var_sfx += $$lib
}
}
QMAKE_USE$$var_sfx += $$MODULE_USES
@ -295,7 +289,8 @@ contains(all_qt_module_deps, qml): \
for (key, IMPORTS._KEYS_) {
PATH = $$eval(IMPORTS.$${key}.path)
PLUGIN = $$eval(IMPORTS.$${key}.plugin)
!isEmpty(PATH):!isEmpty(PLUGIN): LIBS *= -L$$PATH -l$${PLUGIN}$$qtPlatformTargetSuffix()
!isEmpty(PATH):!isEmpty(PLUGIN): \
LIBS += $$PATH/$$QMAKE_PREFIX_STATICLIB$${PLUGIN}$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB
}
# create qml_plugin_import.cpp

View File

@ -1,13 +1,21 @@
QT_FOR_CONFIG += gui
defineTest(prependOpenGlLib) {
path = $$QT.core.libs/$$QMAKE_PREFIX_STATICLIB$$1
ext = .$$QMAKE_EXTENSION_STATICLIB
QMAKE_LIBS_OPENGL_ES2 = $${path}$${ext} $$QMAKE_LIBS_OPENGL_ES2
QMAKE_LIBS_OPENGL_ES2_DEBUG = $${path}d$${ext} $$QMAKE_LIBS_OPENGL_ES2_DEBUG
export(QMAKE_LIBS_OPENGL_ES2)
export(QMAKE_LIBS_OPENGL_ES2_DEBUG)
}
qtConfig(opengles2) {
# Depending on the configuration we use libQtANGLE or libEGL and libGLESv2
qtConfig(combined-angle-lib) {
QMAKE_LIBS_OPENGL_ES2 = -l$${LIBQTANGLE_NAME} $$QMAKE_LIBS_OPENGL_ES2
QMAKE_LIBS_OPENGL_ES2_DEBUG = -l$${LIBQTANGLE_NAME}d $$QMAKE_LIBS_OPENGL_ES2_DEBUG
prependOpenGlLib($$LIBQTANGLE_NAME)
} else {
QMAKE_LIBS_OPENGL_ES2 = -l$${LIBEGL_NAME} -l$${LIBGLESV2_NAME} $$QMAKE_LIBS_OPENGL_ES2
QMAKE_LIBS_OPENGL_ES2_DEBUG = -l$${LIBEGL_NAME}d -l$${LIBGLESV2_NAME}d $$QMAKE_LIBS_OPENGL_ES2_DEBUG
prependOpenGlLib($$LIBGLESV2_NAME)
prependOpenGlLib($$LIBEGL_NAME)
}
# For Desktop, use the ANGLE library location passed on from configure.
INCLUDEPATH += $$QMAKE_INCDIR_OPENGL_ES2

View File

@ -6,10 +6,9 @@ contains(TEMPLATE, ".*app") {
qt:for(entryLib, $$list($$unique(QMAKE_LIBS_QT_ENTRY))) {
isEqual(entryLib, -lqtmain) {
!contains(QMAKE_DEFAULT_LIBDIRS, $$QT.core.libs): \
QMAKE_LIBS += -L$$QT.core.libs
CONFIG(debug, debug|release): QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX}d
else: QMAKE_LIBS += $${entryLib}$${QT_LIBINFIX}
lib = $$QT.core.libs/$${QMAKE_PREFIX_STATICLIB}qtmain$$QT_LIBINFIX$$qtPlatformTargetSuffix().$$QMAKE_EXTENSION_STATICLIB
PRE_TARGETDEPS += $$lib
QMAKE_LIBS += $$lib
} else {
QMAKE_LIBS += $${entryLib}
}

View File

@ -13,7 +13,6 @@ load(qt_config)
QMAKE_LIBS_THREAD += -lrt
QMAKE_LSB = 1
QMAKE_CC = lsbcc
QMAKE_CXX = lsbc++

View File

@ -310,9 +310,18 @@ static QString readSymLink(const QFileSystemEntry &link)
const wchar_t* PathBuffer = &rdb->SymbolicLinkReparseBuffer.PathBuffer[offset];
result = QString::fromWCharArray(PathBuffer, length);
}
// cut-off "//?/" and "/??/"
if (result.size() > 4 && result.at(0) == QLatin1Char('\\') && result.at(2) == QLatin1Char('?') && result.at(3) == QLatin1Char('\\'))
// cut-off "\\?\" and "\??\"
if (result.size() > 4
&& result.at(0) == QLatin1Char('\\')
&& result.at(2) == QLatin1Char('?')
&& result.at(3) == QLatin1Char('\\')) {
result = result.mid(4);
// cut off UNC in addition when the link points at a UNC share
// in which case we need to prepend another backslash to get \\server\share
if (result.leftRef(3) == QLatin1String("UNC")) {
result.replace(0, 3, QLatin1Char('\\'));
}
}
}
free(rdb);
CloseHandle(handle);

View File

@ -523,7 +523,7 @@ struct Q_CORE_EXPORT QMetaObject
Qt::ConnectionType type = Qt::AutoConnection, decltype(function()) *ret = nullptr)
{
return invokeMethodImpl(context,
new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function),
new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
type,
ret);
}
@ -535,7 +535,7 @@ struct Q_CORE_EXPORT QMetaObject
invokeMethod(QObject *context, Func function, typename std::result_of<Func()>::type *ret)
{
return invokeMethodImpl(context,
new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(function),
new QtPrivate::QFunctorSlotObjectWithNoArgs<Func, decltype(function())>(std::move(function)),
Qt::AutoConnection,
ret);
}

View File

@ -2482,6 +2482,17 @@ QString QLocale::toString(double i, char f, int prec) const
Returns a QLocale object initialized to the "C" locale.
This locale is based on en_US but with various quirks of its own, such as
simplified number formatting and its own date formatting. It implements the
POSIX standards that describe the behavior of standard library functions of
the "C" programming language.
Among other things, this means its collation order is based on the ASCII
values of letters, so that (for case-sensitive sorting) all upper-case
letters sort before any lower-case one (rather than each letter's upper- and
lower-case forms sorting adjacent to one another, before the next letter's
two forms).
\sa system()
*/

View File

@ -104,7 +104,7 @@
This enumerated type is used to specify a language.
\value AnyLanguage
\value C The "C" locale is identical in behavior to English/UnitedStates.
\value C A simplified English locale; see QLocale::c()
\value Abkhazian
\value Afan Obsolete, please use Oromo

View File

@ -46,6 +46,8 @@
#include "qwindow.h"
#include "qplatformwindow.h"
#include <private/qwindow_p.h>
QT_BEGIN_NAMESPACE
/*!
@ -199,12 +201,18 @@ void QOffscreenSurface::create()
if (QThread::currentThread() != qGuiApp->thread())
qWarning("Attempting to create QWindow-based QOffscreenSurface outside the gui thread. Expect failures.");
d->offscreenWindow = new QWindow(d->screen);
// Make the window frameless to prevent Windows from enlarging it, should it
// violate the minimum title bar width on the platform.
d->offscreenWindow->setFlags(d->offscreenWindow->flags()
| Qt::CustomizeWindowHint | Qt::FramelessWindowHint);
d->offscreenWindow->setObjectName(QLatin1String("QOffscreenSurface"));
// Remove this window from the global list since we do not want it to be destroyed when closing the app.
// The QOffscreenSurface has to be usable even after exiting the event loop.
QGuiApplicationPrivate::window_list.removeOne(d->offscreenWindow);
d->offscreenWindow->setSurfaceType(QWindow::OpenGLSurface);
d->offscreenWindow->setFormat(d->requestedFormat);
// Prevent QPlatformWindow::initialGeometry() and platforms from setting a default geometry.
qt_window_private(d->offscreenWindow)->setAutomaticPositionAndResizeEnabled(false);
d->offscreenWindow->setGeometry(0, 0, d->size.width(), d->size.height());
d->offscreenWindow->create();
}

View File

@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
QShaderFormat::QShaderFormat() Q_DECL_NOTHROW
: m_api(NoApi)
, m_shaderType(Fragment)
{
}
@ -106,6 +107,9 @@ bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW
if (m_version < other.m_version)
return false;
if (m_shaderType != other.m_shaderType)
return false;
const auto containsAllExtensionsFromOther = std::includes(m_extensions.constBegin(),
m_extensions.constEnd(),
other.m_extensions.constBegin(),
@ -119,12 +123,23 @@ bool QShaderFormat::supports(const QShaderFormat &other) const Q_DECL_NOTHROW
return true;
}
QShaderFormat::ShaderType QShaderFormat::shaderType() const Q_DECL_NOTHROW
{
return m_shaderType;
}
void QShaderFormat::setShaderType(QShaderFormat::ShaderType shaderType) Q_DECL_NOTHROW
{
m_shaderType = shaderType;
}
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();
&& lhs.vendor() == rhs.vendor()
&& lhs.shaderType() == rhs.shaderType();
}
QT_END_NAMESPACE

View File

@ -69,6 +69,15 @@ public:
OpenGLES
};
enum ShaderType : int {
Vertex = 0,
TessellationControl,
TessellationEvaluation,
Geometry,
Fragment,
Compute
};
Q_GUI_EXPORT QShaderFormat() Q_DECL_NOTHROW;
Q_GUI_EXPORT Api api() const Q_DECL_NOTHROW;
@ -86,11 +95,15 @@ public:
Q_GUI_EXPORT bool isValid() const Q_DECL_NOTHROW;
Q_GUI_EXPORT bool supports(const QShaderFormat &other) const Q_DECL_NOTHROW;
Q_GUI_EXPORT ShaderType shaderType() const Q_DECL_NOTHROW;
Q_GUI_EXPORT void setShaderType(ShaderType shaderType) Q_DECL_NOTHROW;
private:
Api m_api;
QVersionNumber m_version;
QStringList m_extensions;
QString m_vendor;
ShaderType m_shaderType;
};
Q_GUI_EXPORT bool operator==(const QShaderFormat &lhs, const QShaderFormat &rhs) Q_DECL_NOTHROW;

View File

@ -40,6 +40,7 @@
#include "qshadergenerator_p.h"
#include "qshaderlanguage_p.h"
#include <QRegularExpression>
QT_BEGIN_NAMESPACE
@ -56,6 +57,9 @@ namespace
case QShaderLanguage::Const:
return "const";
case QShaderLanguage::Input:
if (format.shaderType() == QShaderFormat::Vertex)
return "attribute";
else
return "varying";
case QShaderLanguage::Output:
return ""; // Although fragment shaders for <=2 only have fixed outputs
@ -314,12 +318,22 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
[enabledLayers] (const QString &s) { return enabledLayers.contains(s); });
};
QVector<QString> globalInputVariables;
const QRegularExpression globalInputExtractRegExp(QStringLiteral("^.*\\s+(\\w+).*;$"));
const QVector<QShaderNode> nodes = graph.nodes();
for (const QShaderNode &node : nodes) {
if (intersectsEnabledLayers(node.layers())) {
const QByteArrayList headerSnippets = node.rule(format).headerSnippets;
for (const QByteArray &snippet : headerSnippets) {
code << replaceParameters(snippet, node, format);
// If node is an input, record the variable name into the globalInputVariables vector
if (node.type() == QShaderNode::Input) {
const QRegularExpressionMatch match = globalInputExtractRegExp.match(QString::fromUtf8(code.last()));
if (match.hasMatch())
globalInputVariables.push_back(match.captured(1));
}
}
}
}
@ -328,6 +342,14 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
code << QByteArrayLiteral("void main()");
code << QByteArrayLiteral("{");
// Table to store temporary variables that should be replaced by global
// variables. This avoids having vec3 v56 = vertexPosition; when we could
// just use vertexPosition directly.
// The added benefit is when having arrays, we don't try to create
// mat4 v38 = skinningPalelette[100] which would be invalid
QHash<QString, QString> localReferencesToGlobalInputs;
const QRegularExpression localToGlobalRegExp(QStringLiteral("^.*\\s+(\\w+)\\s*=\\s*(\\w+).*;$"));
for (const QShaderGraph::Statement &statement : graph.createStatements(enabledLayers)) {
const QShaderNode node = statement.node;
QByteArray line = node.rule(format).substitution;
@ -338,6 +360,9 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
const bool isInput = port.direction == QShaderNodePort::Input;
const int portIndex = statement.portIndex(portDirection, portName);
Q_ASSERT(portIndex >= 0);
const int variableIndex = isInput ? statement.inputs.at(portIndex)
: statement.outputs.at(portIndex);
if (variableIndex < 0)
@ -345,15 +370,51 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers)
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);
const QByteArray substitutionedLine = replaceParameters(line, node, format);
// Record name of temporary variable that possibly references a global input
// We will replace the temporary variables by the matching global variables later
bool isAGlobalInputVariable = false;
if (node.type() == QShaderNode::Input) {
const QRegularExpressionMatch match = localToGlobalRegExp.match(QString::fromUtf8(substitutionedLine));
if (match.hasMatch()) {
const QString globalVariable = match.captured(2);
if (globalInputVariables.contains(globalVariable)) {
const QString localVariable = match.captured(1);
// TO DO: Clean globalVariable (remove brackets ...)
localReferencesToGlobalInputs.insert(localVariable, globalVariable);
isAGlobalInputVariable = true;
}
}
}
// Only insert content for lines aren't inputs or have not matching
// globalVariables for now
if (!isAGlobalInputVariable)
code << QByteArrayLiteral(" ") + substitutionedLine;
}
code << QByteArrayLiteral("}");
code << QByteArray();
return code.join('\n');
// Replace occurrences of local variables which reference a global variable
// by the global variables directly
auto it = localReferencesToGlobalInputs.cbegin();
const auto end = localReferencesToGlobalInputs.cend();
QString codeString = QString::fromUtf8(code.join('\n'));
while (it != end) {
const QRegularExpression r(QStringLiteral("\\b(%1)([\\b|\\.|;|\\)|\\[|\\s|\\*|\\+|\\/|\\-|,])").arg(it.key()),
QRegularExpression::MultilineOption);
codeString.replace(r, QStringLiteral("%1\\2").arg(it.value()));
++it;
}
return codeString.toUtf8();
}
QT_END_NAMESPACE

View File

@ -251,6 +251,17 @@ void QShaderNodesLoader::load(const QJsonObject &prototypesObject)
break;
}
// We default out to a Fragment ShaderType if nothing is specified
// as that was the initial behavior we introduced
const QString shaderType = formatObject.value(QStringLiteral("shaderType")).toString();
format.setShaderType(shaderType == QStringLiteral("Fragment") ? QShaderFormat::Fragment
: shaderType == QStringLiteral("Vertex") ? QShaderFormat::Vertex
: shaderType == QStringLiteral("TessellationControl") ? QShaderFormat::TessellationControl
: shaderType == QStringLiteral("TessellationEvaluation") ? QShaderFormat::TessellationEvaluation
: shaderType == QStringLiteral("Geometry") ? QShaderFormat::Geometry
: shaderType == QStringLiteral("Compute") ? QShaderFormat::Compute
: QShaderFormat::Fragment);
const QByteArray substitution = substitutionValue.toString().toUtf8();
const QJsonValue snippetsValue = ruleObject.value(QStringLiteral("headerSnippets"));

View File

@ -268,7 +268,7 @@ EGLConfig QEglConfigChooser::chooseConfig()
configureAttributes.append(EGL_OPENGL_ES_BIT);
break;
}
// fall through
Q_FALLTHROUGH();
default:
needsES2Plus = true;
break;

View File

@ -134,7 +134,7 @@ QEGLPlatformContext::QEGLPlatformContext(const QSurfaceFormat &format, QPlatform
void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
{
m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig);
m_format = q_glFormatFromConfig(m_eglDisplay, m_eglConfig, format);
// m_format now has the renderableType() resolved (it cannot be Default anymore)
// but does not yet contain version, profile, options.
m_shareContext = share ? static_cast<QEGLPlatformContext *>(share)->m_eglContext : 0;
@ -248,6 +248,12 @@ void QEGLPlatformContext::adopt(const QVariant &nativeHandle, QPlatformOpenGLCon
value = 0;
eglQueryContext(m_eglDisplay, context, EGL_CONTEXT_CLIENT_TYPE, &value);
if (value == EGL_OPENGL_API || value == EGL_OPENGL_ES_API) {
// if EGL config supports both OpenGL and OpenGL ES render type,
// q_glFormatFromConfig() with the default "referenceFormat" parameter
// will always figure it out as OpenGL render type.
// We can override it to match user's real render type.
if (value == EGL_OPENGL_ES_API)
m_format.setRenderableType(QSurfaceFormat::OpenGLES);
m_api = value;
eglBindAPI(m_api);
} else {

View File

@ -114,8 +114,8 @@ void QTsLibMouseHandler::readMouseData()
int x = sample.x;
int y = sample.y;
// work around missing coordinates on mouse release
if (sample.pressure == 0 && sample.x == 0 && sample.y == 0) {
// coordinates on release events can contain arbitrary values, just ignore them
if (sample.pressure == 0) {
x = m_x;
y = m_y;
}

View File

@ -59,6 +59,7 @@ enum OutputConfiguration {
OutputConfigOff,
OutputConfigPreferred,
OutputConfigCurrent,
OutputConfigSkip,
OutputConfigMode,
OutputConfigModeline
};
@ -191,6 +192,8 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
configuration = OutputConfigPreferred;
} else if (mode == "current") {
configuration = OutputConfigCurrent;
} else if (mode == "skip") {
configuration = OutputConfigSkip;
} else if (sscanf(mode.constData(), "%dx%d@%d", &configurationSize.rwidth(), &configurationSize.rheight(),
&configurationRefresh) == 3)
{
@ -229,6 +232,11 @@ QPlatformScreen *QKmsDevice::createScreenForConnector(drmModeResPtr resources,
return nullptr;
}
if (configuration == OutputConfigSkip) {
qCDebug(qLcKmsDebug) << "Skipping output" << connectorName;
return nullptr;
}
// Get the current mode on the current crtc
drmModeModeInfo crtc_mode;
memset(&crtc_mode, 0, sizeof crtc_mode);

View File

@ -300,7 +300,7 @@ void QGenericEngine::doRequestUpdate()
if (interface.flags() & QNetworkInterface::IsLoopBack)
continue;
#ifndef Q_OS_WINRT
#ifndef Q_OS_WIN
// ignore WLAN interface handled in separate engine
if (qGetInterfaceType(interface.name()) == QNetworkConfiguration::BearerWLAN)
continue;

View File

@ -154,6 +154,7 @@
<< "due to being" << ([self layerExplicitlyRequested] ? "explicitly requested"
: [self shouldUseMetalLayer] ? "needed by surface type" : "enabled by macOS");
[super setLayer:layer];
layer.delegate = self;
}
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy

View File

@ -1087,7 +1087,10 @@ bool QWindowsMimeImage::canConvertFromMime(const FORMATETC &formatetc, const QMi
const QImage image = qvariant_cast<QImage>(mimeData->imageData());
if (image.isNull())
return false;
return cf == CF_DIBV5 || (cf == CF_DIB) || cf == int(CF_PNG);
// QTBUG-64322: Use PNG only for transparent images as otherwise MS PowerPoint
// cannot handle it.
return cf == CF_DIBV5 || cf == CF_DIB
|| (cf == int(CF_PNG) && image.hasAlphaChannel());
}
bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM * pmedium) const

View File

@ -113,6 +113,9 @@ void QWindowsUiaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event
case QAccessible::ValueChanged:
QWindowsUiaMainProvider::notifyValueChange(static_cast<QAccessibleValueChangeEvent *>(event));
break;
case QAccessible::SelectionAdd:
QWindowsUiaMainProvider::notifySelectionChange(event);
break;
case QAccessible::TextAttributeChanged:
case QAccessible::TextColumnChanged:
case QAccessible::TextInserted:

View File

@ -146,9 +146,33 @@ void QWindowsUiaMainProvider::notifyStateChange(QAccessibleStateChangeEvent *eve
void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
// Notifies changes in values of controls supporting the value interface.
if (accessible->role() == QAccessible::ComboBox && accessible->childCount() > 0) {
QAccessibleInterface *listacc = accessible->child(0);
if (listacc && listacc->role() == QAccessible::List) {
int count = listacc->childCount();
for (int i = 0; i < count; ++i) {
QAccessibleInterface *item = listacc->child(i);
if (item && item->text(QAccessible::Name) == event->value()) {
if (!item->state().selected) {
if (QAccessibleActionInterface *actionInterface = item->actionInterface())
actionInterface->doAction(QAccessibleActionInterface::toggleAction());
}
break;
}
}
}
}
if (event->value().type() == QVariant::String) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
// Notifies changes in string values.
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantString(event->value().toString(), &newVal);
QWindowsUiaWrapper::instance()->raiseAutomationPropertyChangedEvent(provider, UIA_ValueValuePropertyId, oldVal, newVal);
}
} else if (QAccessibleValueInterface *valueInterface = accessible->valueInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
// Notifies changes in values of controls supporting the value interface.
VARIANT oldVal, newVal;
clearVariant(&oldVal);
setVariantDouble(valueInterface->currentValue().toDouble(), &newVal);
@ -158,6 +182,15 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve
}
}
void QWindowsUiaMainProvider::notifySelectionChange(QAccessibleEvent *event)
{
if (QAccessibleInterface *accessible = event->accessibleInterface()) {
if (QWindowsUiaMainProvider *provider = providerForAccessible(accessible)) {
QWindowsUiaWrapper::instance()->raiseAutomationEvent(provider, UIA_SelectionItem_ElementSelectedEventId);
}
}
}
// Notifies changes in text content and selection state of text controls.
void QWindowsUiaMainProvider::notifyTextChange(QAccessibleEvent *event)
{

View File

@ -68,6 +68,7 @@ public:
static void notifyFocusChange(QAccessibleEvent *event);
static void notifyStateChange(QAccessibleStateChangeEvent *event);
static void notifyValueChange(QAccessibleValueChangeEvent *event);
static void notifySelectionChange(QAccessibleEvent *event);
static void notifyTextChange(QAccessibleEvent *event);
// IUnknown

View File

@ -1156,66 +1156,6 @@ static QStyleHelper::WidgetSizePolicy qt_aqua_guess_size(const QWidget *widg, QS
}
#endif
static NSColor *qt_convertColorForContext(CGContextRef context, NSColor *color)
{
Q_ASSERT(color);
Q_ASSERT(context);
CGColorSpaceRef targetCGColorSpace = CGBitmapContextGetColorSpace(context);
NSColorSpace *targetNSColorSpace = [[NSColorSpace alloc] initWithCGColorSpace:targetCGColorSpace];
NSColor *adjusted = [color colorUsingColorSpace:targetNSColorSpace];
[targetNSColorSpace release];
return adjusted;
}
static NSColor *qt_colorForContext(CGContextRef context, const CGFloat (&rgba)[4])
{
Q_ASSERT(context);
auto colorSpace = CGBitmapContextGetColorSpace(context);
if (!colorSpace)
return nil;
return qt_convertColorForContext(context, [NSColor colorWithSRGBRed:rgba[0] green:rgba[1] blue:rgba[2] alpha:rgba[3]]);
}
static void qt_drawDisclosureButton(CGContextRef context, NSInteger state, bool selected, CGRect rect)
{
Q_ASSERT(context);
static const CGFloat gray[] = {0.55, 0.55, 0.55, 0.97};
static const CGFloat white[] = {1.0, 1.0, 1.0, 0.9};
NSColor *fillColor = qt_colorForContext(context, selected ? white : gray);
[fillColor setFill];
if (state == NSOffState) {
static NSBezierPath *triangle = [[NSBezierPath alloc] init];
[triangle removeAllPoints];
// In off state, a disclosure button is an equilateral triangle
// ('pointing' to the right) with a bound rect that can be described
// as NSMakeRect(0, 0, 8, 9). Inside the 'rect' it's translated by
// (2, 4).
[triangle moveToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4)];
[triangle lineToPoint:NSMakePoint(rect.origin.x + 2, rect.origin.y + 4 + 9)];
[triangle lineToPoint:NSMakePoint(rect.origin.x + 2 + 8, rect.origin.y + 4 + 4.5)];
[triangle closePath];
[triangle fill];
} else {
static NSBezierPath *openTriangle = [[NSBezierPath alloc] init];
[openTriangle removeAllPoints];
// In 'on' state, the button is an equilateral triangle (looking down)
// with the bounding rect NSMakeRect(0, 0, 9, 8). Inside the 'rect'
// it's translated by (1, 4).
[openTriangle moveToPoint:NSMakePoint(rect.origin.x + 1, rect.origin.y + 4 + 8)];
[openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 9, rect.origin.y + 4 + 8)];
[openTriangle lineToPoint:NSMakePoint(rect.origin.x + 1 + 4.5, rect.origin.y + 4)];
[openTriangle closePath];
[openTriangle fill];
}
}
void QMacStylePrivate::drawFocusRing(QPainter *p, const QRectF &targetRect, int hMargin, int vMargin, const CocoaControl &cw) const
{
QPainterPath focusRingPath;
@ -3301,15 +3241,8 @@ void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPai
CGContextScaleCTM(cg, 1, -1);
CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave && !qt_mac_applicationIsInDarkMode()) {
// When the real system theme is one of the 'Dark' themes, and an application forces the 'Aqua' theme,
// under some conditions (see QTBUG-74515 for more details) NSButtonCell seems to select the 'Dark'
// code path and is becoming transparent, thus 'invisible' on the white background. To workaround this,
// we draw the disclose triangle manually:
qt_drawDisclosureButton(cg, triangleCell.state, (opt->state & State_Selected) && viewHasFocus, rect);
} else {
[triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
}
d->restoreNSGraphicsContext(cg);
break; }

View File

@ -11343,7 +11343,7 @@ void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
}
// sourceRect must be in the given coordinate system
QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const
QRectF QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const
{
QRectF effectRectF;
@ -11371,7 +11371,7 @@ QRect QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem sy
*unpadded = true;
}
return effectRectF.toAlignedRect();
return effectRectF;
}
QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset,
@ -11389,7 +11389,8 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP
bool unpadded;
const QRectF sourceRect = boundingRect(system);
QRect effectRect = paddedEffectRect(system, mode, sourceRect, &unpadded);
QRectF effectRectF = paddedEffectRect(system, mode, sourceRect, &unpadded);
QRect effectRect = effectRectF.toAlignedRect();
if (offset)
*offset = effectRect.topLeft();
@ -11405,7 +11406,9 @@ QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QP
if (effectRect.isEmpty())
return QPixmap();
QPixmap pixmap(effectRect.size());
const auto dpr = info ? info->painter->device()->devicePixelRatioF() : 1.0;
QPixmap pixmap(QRectF(effectRectF.topLeft(), effectRectF.size() * dpr).toAlignedRect().size());
pixmap.setDevicePixelRatio(dpr);
pixmap.fill(Qt::transparent);
QPainter pixmapPainter(&pixmap);
pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing);

View File

@ -644,7 +644,7 @@ public:
QPixmap pixmap(Qt::CoordinateSystem system,
QPoint *offset,
QGraphicsEffect::PixmapPadMode mode) const override;
QRect paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = 0) const;
QRectF paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded = 0) const;
QGraphicsItem *item;
QGraphicsItemPaintInfo *info;

View File

@ -4852,7 +4852,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
&& painter->worldTransform().type() <= QTransform::TxTranslate)
{
QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect);
QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect).toAlignedRect();
sourced->setCachedOffset(effectRect.topLeft());
} else {

View File

@ -1448,6 +1448,7 @@ bool QOpenGLWidget::event(QEvent *e)
{
// Special case: did grabFramebuffer() for a hidden widget that then became visible.
// Recreate all resources since the context now needs to share with the TLW's.
if (!qGuiApp->testAttribute(Qt::AA_ShareOpenGLContexts))
d->reset();
}
if (!d->initialized && !size().isEmpty() && window()->windowHandle()) {

View File

@ -2908,7 +2908,10 @@ void QStyleSheetStyle::polish(QPalette &pal)
void QStyleSheetStyle::repolish(QWidget *w)
{
QList<const QObject *> children = w->findChildren<const QObject *>(QString());
QList<const QObject *> children;
children.reserve(w->children().size() + 1);
for (auto child: qAsConst(w->children()))
children.append(child);
children.append(w);
styleSheetCaches->styleSheetCache.remove(w);
updateObjects(children);

View File

@ -1239,6 +1239,8 @@ void QPlainTextEditPrivate::ensureViewportLayouted()
This property gets and sets the plain text editor's contents. The previous
contents are removed and undo/redo history is reset when this property is set.
currentCharFormat() is also reset, unless textCursor() is already at the
beginning of the document.
By default, for an editor with no contents, this property contains an empty string.
*/
@ -1518,7 +1520,12 @@ void QPlainTextEdit::paste()
/*!
Deletes all the text in the text edit.
Note that the undo/redo history is cleared by this function.
Notes:
\list
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa cut(), setPlainText()
*/
@ -1651,7 +1658,12 @@ void QPlainTextEdit::timerEvent(QTimerEvent *e)
\a text is interpreted as plain text.
Note that the undo/redo history is cleared by this function.
Notes:
\list
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa toPlainText()
*/

View File

@ -556,7 +556,8 @@ void QTextEditPrivate::_q_ensureVisible(const QRectF &_rect)
This property gets and sets the text editor's contents as plain
text. Previous contents are removed and undo/redo history is reset
when the property is set.
when the property is set. currentCharFormat() is also reset, unless
textCursor() is already at the beginning of the document.
If the text edit has another content type, it will not be replaced
by plain text if you call toPlainText(). The only exception to this
@ -1034,7 +1035,12 @@ void QTextEdit::paste()
/*!
Deletes all the text in the text edit.
Note that the undo/redo history is cleared by this function.
Notes:
\list
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa cut(), setPlainText(), setHtml()
*/
@ -1139,9 +1145,13 @@ void QTextEdit::timerEvent(QTimerEvent *e)
Changes the text of the text edit to the string \a text.
Any previous text is removed.
\a text is interpreted as plain text.
Note that the undo/redo history is cleared by this function.
Notes:
\list
\li \a text is interpreted as plain text.
\li The undo/redo history is also cleared.
\li currentCharFormat() is reset, unless textCursor()
is already at the beginning of the document.
\endlist
\sa toPlainText()
*/
@ -1175,7 +1185,8 @@ QString QTextEdit::toPlainText() const
setHtml() changes the text of the text edit. Any previous text is
removed and the undo/redo history is cleared. The input text is
interpreted as rich text in html format.
interpreted as rich text in html format. currentCharFormat() is also
reset, unless textCursor() is already at the beginning of the document.
\note It is the responsibility of the caller to make sure that the
text is correctly decoded when a QString containing HTML is created

View File

@ -1559,6 +1559,16 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data()
<< NtfsTestResource(NtfsTestResource::SymLink, relToRelSymlink, relToRelTarget)
<< relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath();
}
{
// Symlink to UNC share
pwd.mkdir("unc");
QString errorMessage;
QString uncTarget = QStringLiteral("//") + QtNetworkSettings::winServerName() + "/testshare";
QString uncSymlink = QDir::toNativeSeparators(pwd.absolutePath().append("\\unc\\link_to_unc"));
QTest::newRow("UNC symlink")
<< NtfsTestResource(NtfsTestResource::SymLink, uncSymlink, uncTarget)
<< QDir::fromNativeSeparators(uncSymlink) << true << QDir::fromNativeSeparators(uncTarget) << uncTarget;
}
//Junctions
QString target = "target";
@ -1630,7 +1640,7 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks()
// Ensure that junctions, mountpoints are removed. If this fails, do not remove
// temporary directory to prevent it from trashing the system.
if (fi.isDir()) {
if (!QDir().rmdir(fi.fileName())) {
if (!QDir().rmdir(fi.filePath())) {
qWarning("Unable to remove NTFS junction '%s'', keeping '%s'.",
qPrintable(fi.fileName()), qPrintable(QDir::toNativeSeparators(m_dir.path())));
m_dir.setAutoRemove(false);

View File

@ -1,4 +1,5 @@
CONFIG += testcase
qtConfig(c++14): CONFIG += c++14
TARGET = tst_qmetaobject
QT = core-private testlib
SOURCES = tst_qmetaobject.cpp

View File

@ -816,6 +816,15 @@ void tst_QMetaObject::invokePointer()
QCOMPARE(obj.slotResult, QString("sl1:bubu"));
}
QCOMPARE(countedStructObjectsCount, 0);
#ifdef __cpp_init_captures
{
CountedStruct str;
std::unique_ptr<int> ptr( new int );
QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj, p = std::move(ptr)]() { obj.sl1(t1); }));
QCOMPARE(obj.slotResult, QString("sl1:1"));
}
QCOMPARE(countedStructObjectsCount, 0);
#endif
}
void tst_QMetaObject::invokeQueuedMetaMember()
@ -1121,6 +1130,15 @@ void tst_QMetaObject::invokeBlockingQueuedPointer()
QCOMPARE(exp, QString("yessir"));
QCOMPARE(obj.slotResult, QString("sl1:bubu"));
}
#ifdef __cpp_init_captures
{
std::unique_ptr<int> ptr(new int);
QVERIFY(QMetaObject::invokeMethod(&obj,
[&obj, p = std::move(ptr)]() { return obj.sl1("hehe"); },
Qt::BlockingQueuedConnection));
QCOMPARE(obj.slotResult, QString("sl1:hehe"));
}
#endif
QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection));
t.quit();
QVERIFY(t.wait());

View File

@ -35,11 +35,13 @@
namespace
{
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion)
QShaderFormat createFormat(QShaderFormat::Api api, int majorVersion, int minorVersion,
QShaderFormat::ShaderType shaderType= QShaderFormat::Fragment)
{
auto format = QShaderFormat();
format.setApi(api);
format.setVersion(QVersionNumber(majorVersion, minorVersion));
format.setShaderType(shaderType);
return format;
}
@ -74,7 +76,7 @@ namespace
return edge;
}
QShaderGraph createGraph()
QShaderGraph createFragmentShaderGraph()
{
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
@ -194,6 +196,7 @@ private slots:
void shouldProcessLanguageQualifierAndTypeEnums_data();
void shouldProcessLanguageQualifierAndTypeEnums();
void shouldGenerateDifferentCodeDependingOnActiveLayers();
void shouldUseGlobalVariableRatherThanTemporaries();
};
void tst_QShaderGenerator::shouldHaveDefaultState()
@ -213,7 +216,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
QTest::addColumn<QShaderFormat>("format");
QTest::addColumn<QByteArray>("expectedCode");
const auto graph = createGraph();
const auto graph = createFragmentShaderGraph();
const auto openGLES2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
const auto openGL3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0);
@ -234,14 +237,9 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
<< ""
<< "void main()"
<< "{"
<< " highp vec2 v2 = texCoord;"
<< " sampler2D v1 = texture;"
<< " highp float v3 = lightIntensity;"
<< " highp vec4 v5 = texture2D(v1, v2);"
<< " highp vec3 v0 = worldPosition;"
<< " highp float v4 = exposure;"
<< " highp vec4 v6 = lightModel(v5, v0, v3);"
<< " highp vec4 v7 = v6 * pow(2.0, v4);"
<< " highp vec4 v5 = texture2D(texture, texCoord);"
<< " highp vec4 v6 = lightModel(v5, worldPosition, lightIntensity);"
<< " highp vec4 v7 = v6 * pow(2.0, exposure);"
<< " gl_fragColor = v7;"
<< "}"
<< "";
@ -256,14 +254,9 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data()
<< ""
<< "void main()"
<< "{"
<< " vec2 v2 = texCoord;"
<< " sampler2D v1 = texture;"
<< " float v3 = lightIntensity;"
<< " vec4 v5 = texture2D(v1, v2);"
<< " vec3 v0 = worldPosition;"
<< " float v4 = exposure;"
<< " vec4 v6 = lightModel(v5, v0, v3);"
<< " vec4 v7 = v6 * pow(2.0, v4);"
<< " vec4 v5 = texture2D(texture, texCoord);"
<< " vec4 v6 = lightModel(v5, worldPosition, lightIntensity);"
<< " vec4 v7 = v6 * pow(2.0, exposure);"
<< " fragColor = v7;"
<< "}"
<< "";
@ -580,6 +573,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
QTest::addColumn<QShaderFormat>("format");
QTest::addColumn<QByteArray>("expectedCode");
{
const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0);
const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0);
const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0);
@ -633,8 +627,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< ""
<< "void main()"
<< "{"
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " gl_fragColor = v0;"
<< " gl_fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto gl3Code = (QByteArrayList() << "#version 130"
@ -646,8 +639,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< ""
<< "void main()"
<< "{"
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " fragColor = v0;"
<< " fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto gl4Code = (QByteArrayList() << "#version 400 core"
@ -659,8 +651,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< ""
<< "void main()"
<< "{"
<< QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " fragColor = v0;"
<< " fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto es2Code = (QByteArrayList() << "#version 100"
@ -671,8 +662,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< ""
<< "void main()"
<< "{"
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " gl_fragColor = v0;"
<< " gl_fragColor = worldPosition;"
<< "}"
<< "").join("\n");
const auto es3Code = (QByteArrayList() << "#version 300 es"
@ -683,8 +673,7 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
<< ""
<< "void main()"
<< "{"
<< QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8()
<< " gl_fragColor = v0;"
<< " gl_fragColor = worldPosition;"
<< "}"
<< "").join("\n");
@ -697,6 +686,80 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data()
}
}
{
const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0, QShaderFormat::Vertex);
const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0, QShaderFormat::Vertex);
const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0, QShaderFormat::Vertex);
const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0, QShaderFormat::Vertex);
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0, QShaderFormat::Vertex);
auto graph = QShaderGraph();
auto vertexPosition = createNode({
createPort(QShaderNodePort::Output, "value")
});
vertexPosition.setParameter("name", "vertexPosition");
vertexPosition.setParameter("qualifier", QVariant::fromValue<QShaderLanguage::StorageQualifier>(QShaderLanguage::Input));
vertexPosition.setParameter("type", QVariant::fromValue<QShaderLanguage::VariableType>(QShaderLanguage::Vec4));
vertexPosition.addRule(es2, QShaderNode::Rule("",
QByteArrayList() << "$qualifier highp $type $name;"));
vertexPosition.addRule(gl2, QShaderNode::Rule("",
QByteArrayList() << "$qualifier $type $name;"));
vertexPosition.addRule(gl3, QShaderNode::Rule("",
QByteArrayList() << "$qualifier $type $name;"));
graph.addNode(vertexPosition);
const auto gl2Code = (QByteArrayList() << "#version 110"
<< ""
<< "attribute vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
<< "}"
<< "").join("\n");
const auto gl3Code = (QByteArrayList() << "#version 130"
<< ""
<< "in vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
<< "}"
<< "").join("\n");
const auto gl4Code = (QByteArrayList() << "#version 400 core"
<< ""
<< "in vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
<< "}"
<< "").join("\n");
const auto es2Code = (QByteArrayList() << "#version 100"
<< ""
<< "attribute highp vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
<< "}"
<< "").join("\n");
const auto es3Code = (QByteArrayList() << "#version 300 es"
<< ""
<< "in highp vec4 vertexPosition;"
<< ""
<< "void main()"
<< "{"
<< "}"
<< "").join("\n");
QTest::addRow("Attribute header substitution ES2") << graph << es2 << es2Code;
QTest::addRow("Attribute header substitution ES3") << graph << es3 << es3Code;
QTest::addRow("Attribute header substitution GL2") << graph << gl2 << gl2Code;
QTest::addRow("Attribute header substitution GL3") << graph << gl3 << gl3Code;
QTest::addRow("Attribute header substitution GL4") << graph << gl4 << gl4Code;
}
}
void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums()
{
// GIVEN
@ -806,9 +869,7 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< ""
<< "void main()"
<< "{"
<< " vec3 v1 = normalUniform;"
<< " vec4 v0 = diffuseUniform;"
<< " vec4 v2 = lightModel(v0, v1);"
<< " vec4 v2 = lightModel(diffuseUniform, normalUniform);"
<< " fragColor = v2;"
<< "}"
<< "";
@ -831,10 +892,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< ""
<< "void main()"
<< "{"
<< " vec2 v0 = texCoord;"
<< " vec3 v2 = texture2D(normalTexture, v0).rgb;"
<< " vec4 v1 = diffuseUniform;"
<< " vec4 v3 = lightModel(v1, v2);"
<< " vec3 v2 = texture2D(normalTexture, texCoord).rgb;"
<< " vec4 v3 = lightModel(diffuseUniform, v2);"
<< " fragColor = v3;"
<< "}"
<< "";
@ -857,10 +916,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< ""
<< "void main()"
<< "{"
<< " vec2 v0 = texCoord;"
<< " vec3 v2 = normalUniform;"
<< " vec4 v1 = texture2D(diffuseTexture, v0);"
<< " vec4 v3 = lightModel(v1, v2);"
<< " vec4 v1 = texture2D(diffuseTexture, texCoord);"
<< " vec4 v3 = lightModel(v1, normalUniform);"
<< " fragColor = v3;"
<< "}"
<< "";
@ -883,9 +940,8 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
<< ""
<< "void main()"
<< "{"
<< " vec2 v0 = texCoord;"
<< " vec3 v2 = texture2D(normalTexture, v0).rgb;"
<< " vec4 v1 = texture2D(diffuseTexture, v0);"
<< " vec3 v2 = texture2D(normalTexture, texCoord).rgb;"
<< " vec4 v1 = texture2D(diffuseTexture, texCoord);"
<< " vec4 v3 = lightModel(v1, v2);"
<< " fragColor = v3;"
<< "}"
@ -894,6 +950,133 @@ void tst_QShaderGenerator::shouldGenerateDifferentCodeDependingOnActiveLayers()
}
}
void tst_QShaderGenerator::shouldUseGlobalVariableRatherThanTemporaries()
{
// GIVEN
const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0);
{
// WHEN
auto vertexPosition = createNode({
createPort(QShaderNodePort::Output, "vertexPosition")
});
vertexPosition.addRule(gl4, QShaderNode::Rule("vec4 $vertexPosition = vertexPosition;",
QByteArrayList() << "in vec4 vertexPosition;"));
auto fakeMultiPlyNoSpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeMultiPlyNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName*v11;"));
auto fakeMultiPlySpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeMultiPlySpace.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName * v11;"));
auto fakeJoinNoSpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeJoinNoSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz,$varName.w);"));
auto fakeJoinSpace = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeJoinSpace.addRule(gl4, QShaderNode::Rule("vec4 $out = vec4($varName.xyz, $varName.w);"));
auto fakeAdd = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeAdd.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw + $varName;"));
auto fakeSub = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeSub.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName.xyzw - $varName;"));
auto fakeDiv = createNode({
createPort(QShaderNodePort::Input, "varName"),
createPort(QShaderNodePort::Output, "out")
});
fakeDiv.addRule(gl4, QShaderNode::Rule("vec4 $out = $varName / v0;"));
auto fragColor = createNode({
createPort(QShaderNodePort::Input, "input1"),
createPort(QShaderNodePort::Input, "input2"),
createPort(QShaderNodePort::Input, "input3"),
createPort(QShaderNodePort::Input, "input4"),
createPort(QShaderNodePort::Input, "input5"),
createPort(QShaderNodePort::Input, "input6"),
createPort(QShaderNodePort::Input, "input7")
});
fragColor.addRule(gl4, QShaderNode::Rule("fragColor = $input1 + $input2 + $input3 + $input4 + $input5 + $input6 + $input7;",
QByteArrayList() << "out vec4 fragColor;"));
const auto graph = [=] {
auto res = QShaderGraph();
res.addNode(vertexPosition);
res.addNode(fakeMultiPlyNoSpace);
res.addNode(fakeMultiPlySpace);
res.addNode(fakeJoinNoSpace);
res.addNode(fakeJoinSpace);
res.addNode(fakeAdd);
res.addNode(fakeSub);
res.addNode(fakeDiv);
res.addNode(fragColor);
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlyNoSpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeMultiPlySpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinNoSpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeJoinSpace.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeAdd.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeSub.uuid(), "varName"));
res.addEdge(createEdge(vertexPosition.uuid(), "vertexPosition", fakeDiv.uuid(), "varName"));
res.addEdge(createEdge(fakeMultiPlyNoSpace.uuid(), "out", fragColor.uuid(), "input1"));
res.addEdge(createEdge(fakeMultiPlySpace.uuid(), "out", fragColor.uuid(), "input2"));
res.addEdge(createEdge(fakeJoinNoSpace.uuid(), "out", fragColor.uuid(), "input3"));
res.addEdge(createEdge(fakeJoinSpace.uuid(), "out", fragColor.uuid(), "input4"));
res.addEdge(createEdge(fakeAdd.uuid(), "out", fragColor.uuid(), "input5"));
res.addEdge(createEdge(fakeSub.uuid(), "out", fragColor.uuid(), "input6"));
res.addEdge(createEdge(fakeDiv.uuid(), "out", fragColor.uuid(), "input7"));
return res;
}();
auto generator = QShaderGenerator();
generator.graph = graph;
generator.format = gl4;
const auto code = generator.createShaderCode({"diffuseUniform", "normalUniform"});
// THEN
const auto expected = QByteArrayList()
<< "#version 400 core"
<< ""
<< "in vec4 vertexPosition;"
<< "out vec4 fragColor;"
<< ""
<< "void main()"
<< "{"
<< " vec4 v7 = vertexPosition / vertexPosition;"
<< " vec4 v6 = vertexPosition.xyzw - vertexPosition;"
<< " vec4 v5 = vertexPosition.xyzw + vertexPosition;"
<< " vec4 v4 = vec4(vertexPosition.xyz, vertexPosition.w);"
<< " vec4 v3 = vec4(vertexPosition.xyz,vertexPosition.w);"
<< " vec4 v2 = vertexPosition * v11;"
<< " vec4 v1 = vertexPosition*v11;"
<< " fragColor = v1 + v2 + v3 + v4 + v5 + v6 + v7;"
<< "}"
<< "";
QCOMPARE(code, expected.join("\n"));
}
}
QTEST_MAIN(tst_QShaderGenerator)
#include "tst_qshadergenerator.moc"

View File

@ -48,6 +48,7 @@ public:
private slots:
void init();
void repolish();
void repolish_without_crashing();
void numinstances();
void widgetsBeforeAppStyleSheet();
void widgetsAfterAppStyleSheet();
@ -367,6 +368,26 @@ void tst_QStyleSheetStyle::repolish()
QCOMPARE(BACKGROUND(p1), APPBACKGROUND(p1));
}
void tst_QStyleSheetStyle::repolish_without_crashing()
{
// This used to crash, QTBUG-69204
QMainWindow w;
QScopedPointer<QSplitter> splitter1(new QSplitter(w.centralWidget()));
QScopedPointer<QSplitter> splitter2(new QSplitter);
QScopedPointer<QSplitter> splitter3(new QSplitter);
splitter2->addWidget(splitter3.data());
splitter2->setStyleSheet("color: red");
QScopedPointer<QLabel> label(new QLabel);
label->setTextFormat(Qt::RichText);
splitter3->addWidget(label.data());
label->setText("hey");
splitter1->addWidget(splitter2.data());
w.show();
QCOMPARE(COLOR(*label), QColor(Qt::red));
}
void tst_QStyleSheetStyle::widgetStyle()
{
qApp->setStyleSheet(QString());