diff options
author | Nicolas Guichard <nicolas.guichard@kdab.com> | 2020-02-14 12:50:00 +0100 |
---|---|---|
committer | Nicolas Guichard <nicolas.guichard@kdab.com> | 2020-02-20 06:43:03 +0100 |
commit | c2827e617c40440c9ab5086c767b78c9d8b9d8fd (patch) | |
tree | d55dcf6393d4545dc5a9e82371ca3f14fc0bb5d8 /src | |
parent | 27493cc4f20958f03de4099fac8ba2fc05e50364 (diff) |
Fix QShaderGenerator crashing when a node port name prefixed another one
QShaderGenerator didn't handle substitutions like
`vec4 $color = mix($color1, $color2, $fac);`
Note that `$color` is a prefix to `$color1` and `$color2`. For the
substitution `QByteArray::replace` was used so if `$color` was handled
first and replaced by `v1`, `$color1` and `$color2` were never correctly
replaced and instead became `v11` and `v12` which caused a crash later
on.
Change-Id: Idaf800fdac468f33c323eb722701da5f8eb918d6
(cherry picked from commit 49dbe760e4e0d8a781b5336efdce4748a7d73a33)
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gui/util/qshadergenerator.cpp | 42 |
1 files changed, 39 insertions, 3 deletions
diff --git a/src/gui/util/qshadergenerator.cpp b/src/gui/util/qshadergenerator.cpp index bcb985de54..7ea42a7c9a 100644 --- a/src/gui/util/qshadergenerator.cpp +++ b/src/gui/util/qshadergenerator.cpp @@ -42,6 +42,8 @@ #include "qshaderlanguage_p.h" #include <QRegularExpression> +#include <cctype> + QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(ShaderGenerator, "ShaderGenerator", QtWarningMsg) @@ -457,6 +459,13 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) QByteArray line = node.rule(format).substitution; const QVector<QShaderNodePort> ports = node.ports(); + struct VariableReplacement { + QByteArray placeholder; + QByteArray variable; + }; + + QVector<VariableReplacement> variableReplacements; + // Generate temporary variable names vN for (const QShaderNodePort &port : ports) { const QString portName = port.name; @@ -472,10 +481,37 @@ QByteArray QShaderGenerator::createShaderCode(const QStringList &enabledLayers) if (variableIndex < 0) continue; - const auto placeholder = QByteArray(QByteArrayLiteral("$") + portName.toUtf8()); - const auto variable = QByteArray(QByteArrayLiteral("v") + QByteArray::number(variableIndex)); + VariableReplacement replacement; + replacement.placeholder = QByteArrayLiteral("$") + portName.toUtf8(); + replacement.variable = QByteArrayLiteral("v") + QByteArray::number(variableIndex); + + variableReplacements.append(std::move(replacement)); + } + + int begin = 0; + while ((begin = line.indexOf('$', begin)) != -1) { + int end = begin + 1; + char endChar = line.at(end); + const int size = line.size(); + while (end < size && (std::isalnum(endChar) || endChar == '_')) { + ++end; + endChar = line.at(end); + } + + const int placeholderLength = end - begin; - line.replace(placeholder, variable); + const QByteArray variableName = line.mid(begin, placeholderLength); + const auto replacementIt = std::find_if(variableReplacements.cbegin(), variableReplacements.cend(), + [&variableName](const VariableReplacement &replacement) { + return variableName == replacement.placeholder; + }); + + if (replacementIt != variableReplacements.cend()) { + line.replace(begin, placeholderLength, replacementIt->variable); + begin += replacementIt->variable.length(); + } else { + begin = end; + } } // Substitute variable names by generated vN variable names |