From 3f17029aa12eafd3f8ddd5e0b246a6bf22eabfe3 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Mon, 4 Feb 2019 17:10:22 +0100 Subject: Fix resolving NTFS symbolic links that point to UNC shares Without this change, the target of a symbolic link that points to a UNC share would include UNC in the target path, and not be correctly made absolute. Add a relevant test case, and use the opportunity to factor out the helper code that creates NTFS symlinks into a function that takes care of error handling. The file created with the new test case only gets cleaned up correctly when passing the file path into QDir::rmdir, which is either way the right thing to do. [ChangeLog][QtCore][QFileInfo] Fixed resolving of symbolic links to UNC shares on NTFS file systems. Change-Id: I9ba75d627aedf7c4cc289f0cb71088d795d30d8a Fixes: QTBUG-73688 Task-number: QTBUG-63970 Task-number: QTBUG-30401 Task-number: QTBUG-20791 Reviewed-by: Thiago Macieira --- tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp | 68 +++++++++++++++-------- 1 file changed, 45 insertions(+), 23 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp index 017eebe153..baf78f6a04 100644 --- a/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp +++ b/tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp @@ -95,6 +95,33 @@ inline bool qIsLikelyToBeNfs(const QString &path) #endif } +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +enum NtfsTargetType { + NtfsTargetFile = 0x0, + NtfsTargetDir = 0x1 +}; + +static bool createNtfsSymLinkHelper(const QString &path, const QString &target, NtfsTargetType targetType) +{ + DWORD dwFlags = targetType; + DWORD err = ERROR_SUCCESS; + + SetLastError(0); + const bool result = CreateSymbolicLink(reinterpret_cast(path.utf16()), + reinterpret_cast(target.utf16()), dwFlags); + err = GetLastError(); + + // CreateSymbolicLink can return TRUE & still fail to create the link, + // the error code in that case might be ERROR_PRIVILEGE_NOT_HELD (1314) + if (!result || err != ERROR_SUCCESS) { + qWarning() << "Error creating NTFS-symlink from:" << path << "to" << target << ":" << qt_error_string(err); + + return false; + } + return true; +} +#endif + static QString seedAndTemplate() { QString base; @@ -704,18 +731,12 @@ void tst_QFileInfo::canonicalFilePath() #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) { - // CreateSymbolicLink can return TRUE & still fail to create the link, - // the error code in that case is ERROR_PRIVILEGE_NOT_HELD (1314) - SetLastError(0); const QString linkTarget = QStringLiteral("res"); - BOOL ret = CreateSymbolicLink((wchar_t*)linkTarget.utf16(), (wchar_t*)m_resourcesDir.utf16(), 1); - DWORD dwErr = GetLastError(); + BOOL ret = createNtfsSymLinkHelper(linkTarget, m_resourcesDir, NtfsTargetDir); if (!ret) QSKIP("Symbolic links aren't supported by FS"); QString currentPath = QDir::currentPath(); bool is_res_Current = QDir::setCurrent(linkTarget); - if (!is_res_Current && dwErr == 1314) - QSKIP("Not enough privilages to create Symbolic links"); QCOMPARE(is_res_Current, true); const QString actualCanonicalPath = QFileInfo("file1").canonicalFilePath(); QVERIFY(QDir::setCurrent(currentPath)); @@ -1482,19 +1503,12 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() file.open(QIODevice::ReadWrite); file.close(); - DWORD err = ERROR_SUCCESS ; + bool result = true; if (!pwd.exists("abs_symlink")) - if (!CreateSymbolicLink((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x1)) - err = GetLastError(); - if (err == ERROR_SUCCESS && !pwd.exists(relSymlink)) - if (!CreateSymbolicLink((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x1)) - err = GetLastError(); - if (err != ERROR_SUCCESS) { - wchar_t errstr[0x100]; - DWORD count = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, - 0, err, 0, errstr, 0x100, 0); - QString error(QString::fromWCharArray(errstr, count)); - qWarning() << error; + result = createNtfsSymLinkHelper(absSymlink, absTarget, NtfsTargetDir); + if (result && !pwd.exists(relSymlink)) + result = createNtfsSymLinkHelper(relSymlink, relTarget, NtfsTargetDir); + if (!result) { //we need at least one data set for the test not to assert fail when skipping _data function QDir target("target"); QTest::newRow("dummy") << target.path() << false << "" << target.canonicalPath(); @@ -1517,13 +1531,21 @@ void tst_QFileInfo::ntfsJunctionPointsAndSymlinks_data() QString relSymlink = "rel_symlink.cpp"; QString relToRelTarget = QDir::toNativeSeparators(relativeDir.relativeFilePath(target.absoluteFilePath())); QString relToRelSymlink = "relative/rel_symlink"; - QVERIFY(pwd.exists("abs_symlink.cpp") || CreateSymbolicLink((wchar_t*)absSymlink.utf16(),(wchar_t*)absTarget.utf16(),0x0)); - QVERIFY(pwd.exists(relSymlink) || CreateSymbolicLink((wchar_t*)relSymlink.utf16(),(wchar_t*)relTarget.utf16(),0x0)); - QVERIFY(pwd.exists(relToRelSymlink) || CreateSymbolicLink((wchar_t*)relToRelSymlink.utf16(), (wchar_t*)relToRelTarget.utf16(),0x0)); + QVERIFY(pwd.exists("abs_symlink.cpp") || createNtfsSymLinkHelper(absSymlink, absTarget, NtfsTargetFile)); + QVERIFY(pwd.exists(relSymlink) || createNtfsSymLinkHelper(relSymlink, relTarget, NtfsTargetFile)); + QVERIFY(pwd.exists(relToRelSymlink) || createNtfsSymLinkHelper(relToRelSymlink, relToRelTarget, NtfsTargetFile)); QTest::newRow("absolute file symlink") << absSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); QTest::newRow("relative file symlink") << relSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); QTest::newRow("relative to relative file symlink") << relToRelSymlink << true << QDir::fromNativeSeparators(absTarget) << target.canonicalFilePath(); } + { + // Symlink to UNC share + pwd.mkdir("unc"); + QString uncTarget = QStringLiteral("//") + QtNetworkSettings::winServerName() + "/testshare"; + QString uncSymlink = QDir::toNativeSeparators(pwd.absolutePath().append("\\unc\\link_to_unc")); + QVERIFY(pwd.exists("link_to_unc") || createNtfsSymLinkHelper(uncSymlink, uncTarget, NtfsTargetDir)); + QTest::newRow("UNC symlink") << uncSymlink << true << uncTarget << uncTarget; + } //Junctions QString target = "target"; @@ -1570,7 +1592,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); -- cgit v1.2.3 From 60181f13a35b05bce664ba5f6cfa7a9d6ae2dc7d Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Fri, 29 Mar 2019 10:54:43 +0100 Subject: QShaderGenerator: fix substitution for attributes on GL2/ES2 GL2/ES2 expect it to be attribute and not in like later versions of OpenGL. Task-number: QTBUG-74829 Change-Id: Iddd22386ed315d6e6843d8225e49a4b73b6ad9ba Reviewed-by: Sean Harmer --- .../util/qshadergenerator/tst_qshadergenerator.cpp | 217 ++++++++++++++------- 1 file changed, 147 insertions(+), 70 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index 82197f815e..c873aebef7 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -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); @@ -213,7 +215,7 @@ void tst_QShaderGenerator::shouldGenerateShaderCode_data() QTest::addColumn("format"); QTest::addColumn("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); @@ -580,120 +582,195 @@ void tst_QShaderGenerator::shouldProcessLanguageQualifierAndTypeEnums_data() QTest::addColumn("format"); QTest::addColumn("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); - const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); - const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); - - const auto qualifierEnum = QMetaEnum::fromType(); - const auto typeEnum = QMetaEnum::fromType(); - - for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { - const auto qualifierName = qualifierEnum.key(qualifierIndex); - const auto qualifierValue = static_cast(qualifierEnum.value(qualifierIndex)); + { + const auto es2 = createFormat(QShaderFormat::OpenGLES, 2, 0); + const auto es3 = createFormat(QShaderFormat::OpenGLES, 3, 0); + const auto gl2 = createFormat(QShaderFormat::OpenGLNoProfile, 2, 0); + const auto gl3 = createFormat(QShaderFormat::OpenGLCoreProfile, 3, 0); + const auto gl4 = createFormat(QShaderFormat::OpenGLCoreProfile, 4, 0); + + const auto qualifierEnum = QMetaEnum::fromType(); + const auto typeEnum = QMetaEnum::fromType(); + + for (int qualifierIndex = 0; qualifierIndex < qualifierEnum.keyCount(); qualifierIndex++) { + const auto qualifierName = qualifierEnum.key(qualifierIndex); + const auto qualifierValue = static_cast(qualifierEnum.value(qualifierIndex)); + + for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { + const auto typeName = typeEnum.key(typeIndex); + const auto typeValue = static_cast(typeEnum.value(typeIndex)); + + auto graph = QShaderGraph(); + + auto worldPosition = createNode({ + createPort(QShaderNodePort::Output, "value") + }); + worldPosition.setParameter("name", "worldPosition"); + worldPosition.setParameter("qualifier", QVariant::fromValue(qualifierValue)); + worldPosition.setParameter("type", QVariant::fromValue(typeValue)); + worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;", + QByteArrayList() << "$qualifier highp $type $name;")); + worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;", + QByteArrayList() << "$qualifier $type $name;")); + worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;", + QByteArrayList() << "$qualifier $type $name;")); + + auto fragColor = createNode({ + createPort(QShaderNodePort::Input, "fragColor") + }); + fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;")); + fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;")); + fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;", + QByteArrayList() << "out vec4 fragColor;")); + + graph.addNode(worldPosition); + graph.addNode(fragColor); + + graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor")); + + const auto gl2Code = (QByteArrayList() << "#version 110" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " gl_fragColor = v0;" + << "}" + << "").join("\n"); + const auto gl3Code = (QByteArrayList() << "#version 130" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " fragColor = v0;" + << "}" + << "").join("\n"); + const auto gl4Code = (QByteArrayList() << "#version 400 core" + << "" + << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "out vec4 fragColor;" + << "" + << "void main()" + << "{" + << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " fragColor = v0;" + << "}" + << "").join("\n"); + const auto es2Code = (QByteArrayList() << "#version 100" + << "" + << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " gl_fragColor = v0;" + << "}" + << "").join("\n"); + const auto es3Code = (QByteArrayList() << "#version 300 es" + << "" + << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3)) + .arg(toGlsl(typeValue)) + .toUtf8() + << "" + << "void main()" + << "{" + << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() + << " gl_fragColor = v0;" + << "}" + << "").join("\n"); + + QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code; + QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code; + QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code; + QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code; + QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code; + } + } + } - for (int typeIndex = 0; typeIndex < typeEnum.keyCount(); typeIndex++) { - const auto typeName = typeEnum.key(typeIndex); - const auto typeValue = static_cast(typeEnum.value(typeIndex)); + { + 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 worldPosition = createNode({ + auto vertexPosition = createNode({ createPort(QShaderNodePort::Output, "value") }); - worldPosition.setParameter("name", "worldPosition"); - worldPosition.setParameter("qualifier", QVariant::fromValue(qualifierValue)); - worldPosition.setParameter("type", QVariant::fromValue(typeValue)); - worldPosition.addRule(es2, QShaderNode::Rule("highp $type $value = $name;", + vertexPosition.setParameter("name", "vertexPosition"); + vertexPosition.setParameter("qualifier", QVariant::fromValue(QShaderLanguage::Input)); + vertexPosition.setParameter("type", QVariant::fromValue(QShaderLanguage::Vec4)); + + vertexPosition.addRule(es2, QShaderNode::Rule("", QByteArrayList() << "$qualifier highp $type $name;")); - worldPosition.addRule(gl2, QShaderNode::Rule("$type $value = $name;", + vertexPosition.addRule(gl2, QShaderNode::Rule("", QByteArrayList() << "$qualifier $type $name;")); - worldPosition.addRule(gl3, QShaderNode::Rule("$type $value = $name;", + vertexPosition.addRule(gl3, QShaderNode::Rule("", QByteArrayList() << "$qualifier $type $name;")); - auto fragColor = createNode({ - createPort(QShaderNodePort::Input, "fragColor") - }); - fragColor.addRule(es2, QShaderNode::Rule("gl_fragColor = $fragColor;")); - fragColor.addRule(gl2, QShaderNode::Rule("gl_fragColor = $fragColor;")); - fragColor.addRule(gl3, QShaderNode::Rule("fragColor = $fragColor;", - QByteArrayList() << "out vec4 fragColor;")); - - graph.addNode(worldPosition); - graph.addNode(fragColor); - - graph.addEdge(createEdge(worldPosition.uuid(), "value", fragColor.uuid(), "fragColor")); + graph.addNode(vertexPosition); const auto gl2Code = (QByteArrayList() << "#version 110" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl2)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "attribute vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); const auto gl3Code = (QByteArrayList() << "#version 130" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl3)) - .arg(toGlsl(typeValue)) - .toUtf8() - << "out vec4 fragColor;" + << "in vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" << "}" << "").join("\n"); const auto gl4Code = (QByteArrayList() << "#version 400 core" << "" - << QStringLiteral("%1 %2 worldPosition;").arg(toGlsl(qualifierValue, gl4)) - .arg(toGlsl(typeValue)) - .toUtf8() - << "out vec4 fragColor;" + << "in vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " fragColor = v0;" << "}" << "").join("\n"); const auto es2Code = (QByteArrayList() << "#version 100" << "" - << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es2)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "attribute highp vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); const auto es3Code = (QByteArrayList() << "#version 300 es" << "" - << QStringLiteral("%1 highp %2 worldPosition;").arg(toGlsl(qualifierValue, es3)) - .arg(toGlsl(typeValue)) - .toUtf8() + << "in highp vec4 vertexPosition;" << "" << "void main()" << "{" - << QStringLiteral(" highp %1 v0 = worldPosition;").arg(toGlsl(typeValue)).toUtf8() - << " gl_fragColor = v0;" << "}" << "").join("\n"); - QTest::addRow("%s %s ES2", qualifierName, typeName) << graph << es2 << es2Code; - QTest::addRow("%s %s ES3", qualifierName, typeName) << graph << es3 << es3Code; - QTest::addRow("%s %s GL2", qualifierName, typeName) << graph << gl2 << gl2Code; - QTest::addRow("%s %s GL3", qualifierName, typeName) << graph << gl3 << gl3Code; - QTest::addRow("%s %s GL4", qualifierName, typeName) << graph << gl4 << gl4Code; - } + 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; } } -- cgit v1.2.3 From a552864c3bd138ae6f09bf0d14d416a18498875c Mon Sep 17 00:00:00 2001 From: Paul Lemire Date: Mon, 1 Apr 2019 16:27:39 +0200 Subject: QShaderGenerator: don't generate temporary variables for global inputs Up until now, the QShaderGenerator would create temporary variables for uniform, attributes, const. This change makes it use the global inputs directly rather than relying on the intermediate properties. Change-Id: Ia9497367d61e536969fe87536606f309c286dbb2 Reviewed-by: Sean Harmer --- .../util/qshadergenerator/tst_qshadergenerator.cpp | 186 ++++++++++++++++----- 1 file changed, 146 insertions(+), 40 deletions(-) (limited to 'tests/auto') diff --git a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp index c873aebef7..f8bb0c3851 100644 --- a/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp +++ b/tests/auto/gui/util/qshadergenerator/tst_qshadergenerator.cpp @@ -196,6 +196,7 @@ private slots: void shouldProcessLanguageQualifierAndTypeEnums_data(); void shouldProcessLanguageQualifierAndTypeEnums(); void shouldGenerateDifferentCodeDependingOnActiveLayers(); + void shouldUseGlobalVariableRatherThanTemporaries(); }; void tst_QShaderGenerator::shouldHaveDefaultState() @@ -236,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;" << "}" << ""; @@ -258,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;" << "}" << ""; @@ -636,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" @@ -649,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" @@ -662,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" @@ -674,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" @@ -686,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"); @@ -883,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;" << "}" << ""; @@ -908,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;" << "}" << ""; @@ -934,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;" << "}" << ""; @@ -960,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;" << "}" @@ -971,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" -- cgit v1.2.3 From 21dcb96ddca357a6e8ace4b1c7252ec465e77727 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Mon, 15 Oct 2018 16:39:03 +0200 Subject: QStyleSheetStyle::repolish: only run on direct children When re-parenting, some widgets change their children. For example QLabel, when set to rich text, will not update, until receiving a polish call, at which time getting a list of all children recursively and then trying to call functions on them will crash, since the children change in the middle of this operation. Fixes: QTBUG-69204 Fixes: QTBUG-74667 Change-Id: I95dd83ebeed14c017e22552ddd47658ae8a09353 Reviewed-by: Shawn Rutledge --- .../qstylesheetstyle/tst_qstylesheetstyle.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp index 0e5c40f1b6..8760ed0373 100644 --- a/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp +++ b/tests/auto/widgets/styles/qstylesheetstyle/tst_qstylesheetstyle.cpp @@ -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 splitter1(new QSplitter(w.centralWidget())); + QScopedPointer splitter2(new QSplitter); + QScopedPointer splitter3(new QSplitter); + splitter2->addWidget(splitter3.data()); + + splitter2->setStyleSheet("color: red"); + QScopedPointer 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(""); -- cgit v1.2.3 From 2a815855a9b91a3537ab3d804ad1ee47d741b64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20Beauz=C3=A9e-Luyssen?= Date: Wed, 3 Apr 2019 18:30:43 +0200 Subject: corelib: invokeMethod: Allow non copyable functors to be used [ChangeLog][QtCore][QMetaObject] Non-copyable lambdas can now be used with invokeMethod(). For consistency reasons, the functor object is now always moved. Fixes: QTBUG-69683 Change-Id: I66ff5e21d6d1926f0f7c5f8c304bed1a90b69917 Reviewed-by: Thiago Macieira Reviewed-by: Olivier Goffart (Woboq GmbH) --- tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro | 1 + .../corelib/kernel/qmetaobject/tst_qmetaobject.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'tests/auto') diff --git a/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro b/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro index e7e5a03a86..980c247ab5 100644 --- a/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro +++ b/tests/auto/corelib/kernel/qmetaobject/qmetaobject.pro @@ -1,4 +1,5 @@ CONFIG += testcase +qtConfig(c++14): CONFIG += c++14 TARGET = tst_qmetaobject QT = core-private testlib SOURCES = tst_qmetaobject.cpp diff --git a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp index cfe1443fd3..ac0731b883 100644 --- a/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp +++ b/tests/auto/corelib/kernel/qmetaobject/tst_qmetaobject.cpp @@ -815,6 +815,15 @@ void tst_QMetaObject::invokePointer() QCOMPARE(obj.slotResult, QString("sl1:bubu")); } QCOMPARE(countedStructObjectsCount, 0); +#ifdef __cpp_init_captures + { + CountedStruct str; + std::unique_ptr 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() @@ -1120,6 +1129,15 @@ void tst_QMetaObject::invokeBlockingQueuedPointer() QCOMPARE(exp, QString("yessir")); QCOMPARE(obj.slotResult, QString("sl1:bubu")); } +#ifdef __cpp_init_captures + { + std::unique_ptr 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()); -- cgit v1.2.3