From: Kim Motoyoshi Kalland Date: Tue, 15 Nov 2011 14:59:11 +0000 (+0100) Subject: Fixed QQuickShaderEffect::lookThroughShaderCode(), added autotest. X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=8a04cc7dc6707d3ee11565fe2c3d76fdce98187f;p=konrad%2Fqtdeclarative.git Fixed QQuickShaderEffect::lookThroughShaderCode(), added autotest. Change-Id: I1e4a1589e1482c21eedab4cd052c16b6653344fb Reviewed-by: Gunnar Sletta --- diff --git a/src/declarative/items/qquickshadereffect.cpp b/src/declarative/items/qquickshadereffect.cpp index ea7350d..78c23d4 100644 --- a/src/declarative/items/qquickshadereffect.cpp +++ b/src/declarative/items/qquickshadereffect.cpp @@ -557,39 +557,45 @@ namespace { if (qt_isalpha(s[index])) { // Read identifier. - int identifierIndex = index; + int idIndex = index; ++index; while (qt_isalnum(s[index])) ++index; - int identifierLength = index - identifierIndex; + int idLength = index - idIndex; + + const int attrLen = sizeof("attribute") - 1; + const int uniLen = sizeof("uniform") - 1; + const int loLen = sizeof("lowp") - 1; + const int medLen = sizeof("mediump") - 1; + const int hiLen = sizeof("highp") - 1; switch (expected) { case QualifierIdentifier: - if (qstrncmp("attribute", s + identifierIndex, identifierLength) == 0) { + if (idLength == attrLen && qstrncmp("attribute", s + idIndex, attrLen) == 0) { decl = AttributeQualifier; expected = PrecisionIdentifier; - } else if (qstrncmp("uniform", s + identifierIndex, identifierLength) == 0) { + } else if (idLength == uniLen && qstrncmp("uniform", s + idIndex, uniLen) == 0) { decl = UniformQualifier; expected = PrecisionIdentifier; } break; case PrecisionIdentifier: - if (qstrncmp("lowp", s + identifierIndex, identifierLength) == 0 - || qstrncmp("mediump", s + identifierIndex, identifierLength) == 0 - || qstrncmp("highp", s + identifierIndex, identifierLength) == 0) + if ((idLength == loLen && qstrncmp("lowp", s + idIndex, loLen) == 0) + || (idLength == medLen && qstrncmp("mediump", s + idIndex, medLen) == 0) + || (idLength == hiLen && qstrncmp("highp", s + idIndex, hiLen) == 0)) { expected = TypeIdentifier; break; } // Fall through. case TypeIdentifier: - typeIndex = identifierIndex; - typeLength = identifierLength; + typeIndex = idIndex; + typeLength = idLength; expected = NameIdentifier; break; case NameIdentifier: - nameIndex = identifierIndex; - nameLength = identifierLength; + nameIndex = idIndex; + nameLength = idLength; return index; // Attribute or uniform declaration found. Return result. default: break; diff --git a/src/declarative/items/qquickshadereffect_p.h b/src/declarative/items/qquickshadereffect_p.h index 257fa40..ee38c31 100644 --- a/src/declarative/items/qquickshadereffect_p.h +++ b/src/declarative/items/qquickshadereffect_p.h @@ -64,7 +64,7 @@ class QSGContext; class QSignalMapper; class QQuickCustomMaterialShader; -class QQuickShaderEffect : public QQuickItem +class Q_AUTOTEST_EXPORT QQuickShaderEffect : public QQuickItem { Q_OBJECT Q_PROPERTY(QByteArray fragmentShader READ fragmentShader WRITE setFragmentShader NOTIFY fragmentShaderChanged) diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index f2f127f..7cb9d33 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -83,6 +83,7 @@ QUICKTESTS = \ qquickpincharea \ qquickpositioners \ qquickrepeater \ + qquickshadereffect \ qquickspriteimage \ qquicktext \ qquicktextedit \ diff --git a/tests/auto/declarative/qquickshadereffect/qquickshadereffect.pro b/tests/auto/declarative/qquickshadereffect/qquickshadereffect.pro new file mode 100644 index 0000000..540bbe1 --- /dev/null +++ b/tests/auto/declarative/qquickshadereffect/qquickshadereffect.pro @@ -0,0 +1,8 @@ +CONFIG += testcase +TARGET = tst_qquickshadereffect +SOURCES += tst_qquickshadereffect.cpp + +macx:CONFIG -= app_bundle + +CONFIG += parallel_test +QT += core-private gui-private declarative-private widgets testlib diff --git a/tests/auto/declarative/qquickshadereffect/tst_qquickshadereffect.cpp b/tests/auto/declarative/qquickshadereffect/tst_qquickshadereffect.cpp new file mode 100644 index 0000000..327fecf --- /dev/null +++ b/tests/auto/declarative/qquickshadereffect/tst_qquickshadereffect.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include +#include + +class TestShaderEffect : public QQuickShaderEffect +{ + Q_OBJECT + Q_PROPERTY(QVariant source READ dummyRead NOTIFY dummyChanged) + Q_PROPERTY(QVariant _0aA9zZ READ dummyRead NOTIFY dummyChanged) + Q_PROPERTY(QVariant x86 READ dummyRead NOTIFY dummyChanged) + Q_PROPERTY(QVariant X READ dummyRead NOTIFY dummyChanged) + +public: + QVariant dummyRead() const { return QVariant(); } + bool isConnected(const char *signal) const { return m_signals.contains(signal); } + +protected: + void connectNotify(const char *signal) { m_signals.append(signal); } + void disconnectNotify(const char *signal) { m_signals.removeOne(signal); } + +signals: + void dummyChanged(); + +private: + QList m_signals; +}; + +class tst_qquickshadereffect : public QObject +{ + Q_OBJECT +public: + tst_qquickshadereffect(); + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void lookThroughShaderCode_data(); + void lookThroughShaderCode(); + +private: + enum PresenceFlags { + VertexPresent = 0x01, + TexCoordPresent = 0x02, + MatrixPresent = 0x04, + OpacityPresent = 0x08, + PropertyPresent = 0x10 + }; + + static void installMsgHandler(); + static void uninstallMsgHandler(); + static void msgHandler(QtMsgType type, const char *msg); + static void expectWarning(const char *msg); + + static QtMsgHandler originalMsgHandler; + static QByteArray actualWarnings; + static QByteArray expectedWarnings; +}; + +QtMsgHandler tst_qquickshadereffect::originalMsgHandler = 0; +QByteArray tst_qquickshadereffect::actualWarnings; +QByteArray tst_qquickshadereffect::expectedWarnings; + +void tst_qquickshadereffect::installMsgHandler() +{ + Q_ASSERT(originalMsgHandler == 0); + originalMsgHandler = qInstallMsgHandler(msgHandler); + actualWarnings.clear(); + expectedWarnings.clear(); +} + +void tst_qquickshadereffect::uninstallMsgHandler() +{ + Q_ASSERT(originalMsgHandler != 0); + qInstallMsgHandler(originalMsgHandler); + originalMsgHandler = 0; + QCOMPARE(QString(actualWarnings), QString(expectedWarnings)); // QString for sensible output. +} + +void tst_qquickshadereffect::msgHandler(QtMsgType type, const char *msg) +{ + Q_ASSERT(originalMsgHandler != 0); + if (type == QtWarningMsg) + actualWarnings.append(msg).append('\n'); + originalMsgHandler(type, msg); +} + +void tst_qquickshadereffect::expectWarning(const char *msg) +{ + Q_ASSERT(originalMsgHandler != 0); + expectedWarnings.append(msg).append('\n'); + QTest::ignoreMessage(QtWarningMsg, msg); +} + +tst_qquickshadereffect::tst_qquickshadereffect() +{ +} + +void tst_qquickshadereffect::initTestCase() +{ +} + +void tst_qquickshadereffect::cleanupTestCase() +{ +} + +void tst_qquickshadereffect::lookThroughShaderCode_data() +{ + QTest::addColumn("vertexShader"); + QTest::addColumn("fragmentShader"); + QTest::addColumn("presenceFlags"); + + QTest::newRow("default") + << QByteArray("uniform highp mat4 qt_Matrix; \n" + "attribute highp vec4 qt_Vertex; \n" + "attribute highp vec2 qt_MultiTexCoord0; \n" + "varying highp vec2 qt_TexCoord0; \n" + "void main() { \n" + " qt_TexCoord0 = qt_MultiTexCoord0; \n" + " gl_Position = qt_Matrix * qt_Vertex; \n" + "}") + << QByteArray("varying highp vec2 qt_TexCoord0; \n" + "uniform sampler2D source; \n" + "uniform lowp float qt_Opacity; \n" + "void main() { \n" + " gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; \n" + "}") + << (VertexPresent | TexCoordPresent | MatrixPresent | OpacityPresent | PropertyPresent); + + QTest::newRow("empty") + << QByteArray(" ") // one space -- if completely empty, default will be used instead. + << QByteArray(" ") + << 0; + + + QTest::newRow("inside line comments") + << QByteArray("//uniform highp mat4 qt_Matrix;\n" + "attribute highp vec4 qt_Vertex;\n" + "// attribute highp vec2 qt_MultiTexCoord0;") + << QByteArray("uniform int source; // uniform lowp float qt_Opacity;") + << (VertexPresent | PropertyPresent); + + QTest::newRow("inside block comments") + << QByteArray("/*uniform highp mat4 qt_Matrix;\n" + "*/attribute highp vec4 qt_Vertex;\n" + "/*/attribute highp vec2 qt_MultiTexCoord0;//**/") + << QByteArray("/**/uniform int source; /* uniform lowp float qt_Opacity; */") + << (VertexPresent | PropertyPresent); + + QTest::newRow("inside preprocessor directive") + << QByteArray("#define uniform\nhighp mat4 qt_Matrix;\n" + "attribute highp vec4 qt_Vertex;\n" + "#if\\\nattribute highp vec2 qt_MultiTexCoord0;") + << QByteArray("uniform int source;\n" + " # undef uniform lowp float qt_Opacity;") + << (VertexPresent | PropertyPresent); + + + QTest::newRow("line comments between") + << QByteArray("uniform//foo\nhighp//bar\nmat4//baz\nqt_Matrix;\n" + "attribute//\nhighp//\nvec4//\nqt_Vertex;\n" + " //*/ uniform \n attribute //\\ \n highp //// \n vec2 //* \n qt_MultiTexCoord0;") + << QByteArray("uniform// lowp float qt_Opacity;\nsampler2D source;") + << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent); + + QTest::newRow("block comments between") + << QByteArray("uniform/*foo*/highp/*/bar/*/mat4/**//**/qt_Matrix;\n" + "attribute/**/highp/**/vec4/**/qt_Vertex;\n" + " /* * */ attribute /*///*/ highp /****/ vec2 /**/ qt_MultiTexCoord0;") + << QByteArray("uniform/*/ uniform//lowp/*float qt_Opacity;*/sampler2D source;") + << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent); + + QTest::newRow("preprocessor directive between") + << QByteArray("uniform\n#foo\nhighp\n#bar\nmat4\n#baz\\\nblimey\nqt_Matrix;\n" + "attribute\n#\nhighp\n#\nvec4\n#\nqt_Vertex;\n" + " #uniform \n attribute \n # foo \n highp \n # bar \n vec2 \n#baz \n qt_MultiTexCoord0;") + << QByteArray("uniform\n#if lowp float qt_Opacity;\nsampler2D source;") + << (VertexPresent | TexCoordPresent | MatrixPresent | PropertyPresent); + + QTest::newRow("newline between") + << QByteArray("uniform\nhighp\nmat4\nqt_Matrix\n;\n" + "attribute \t\r\n highp \n vec4 \n\n qt_Vertex ;\n" + " \n attribute \n highp \n vec2 \n qt_Multi\nTexCoord0 \n ;") + << QByteArray("uniform\nsampler2D\nsource;" + "uniform lowp float qt_Opacity;") + << (VertexPresent | MatrixPresent | OpacityPresent | PropertyPresent); + + + QTest::newRow("extra characters #1") + << QByteArray("funiform highp mat4 qt_Matrix;\n" + "attribute highp vec4 qt_Vertex_;\n" + "attribute highp vec2 qqt_MultiTexCoord0;") + << QByteArray("uniformm int source;\n" + "uniform4 lowp float qt_Opacity;") + << 0; + + QTest::newRow("extra characters #2") + << QByteArray("attribute phighp vec4 qt_Vertex;\n" + "attribute highpi vec2 qt_MultiTexCoord0;" + "fattribute highp vec4 qt_Vertex;\n" + "attributed highp vec2 qt_MultiTexCoord0;") + << QByteArray(" ") + << 0; + + QTest::newRow("missing characters #1") + << QByteArray("unifor highp mat4 qt_Matrix;\n" + "attribute highp vec4 qt_Vert;\n" + "attribute highp vec2 MultiTexCoord0;") + << QByteArray("niform int source;\n" + "uniform qt_Opacity;") + << 0; + + QTest::newRow("missing characters #2") + << QByteArray("attribute high vec4 qt_Vertex;\n" + "attribute ighp vec2 qt_MultiTexCoord0;" + "tribute highp vec4 qt_Vertex;\n" + "attrib highp vec2 qt_MultiTexCoord0;") + << QByteArray(" ") + << 0; + + QTest::newRow("precision") + << QByteArray("uniform mat4 qt_Matrix;\n" + "attribute kindofhighp vec4 qt_Vertex;\n" + "attribute highp qt_MultiTexCoord0;\n") + << QByteArray("uniform lowp float qt_Opacity;\n" + "uniform mediump float source;\n") + << (MatrixPresent | OpacityPresent | PropertyPresent); + + + QTest::newRow("property name #1") + << QByteArray("uniform highp vec3 _0aA9zZ;") + << QByteArray(" ") + << int(PropertyPresent); + + QTest::newRow("property name #2") + << QByteArray("uniform mediump vec2 x86;") + << QByteArray(" ") + << int(PropertyPresent); + + QTest::newRow("property name #3") + << QByteArray("uniform lowp float X;") + << QByteArray(" ") + << int(PropertyPresent); +} + +void tst_qquickshadereffect::lookThroughShaderCode() +{ + QFETCH(QByteArray, vertexShader); + QFETCH(QByteArray, fragmentShader); + QFETCH(int, presenceFlags); + + TestShaderEffect item; + QVERIFY(!item.isConnected(SIGNAL(dummyChanged()))); // Nothing connected yet. + + installMsgHandler(); + if ((presenceFlags & VertexPresent) == 0) + expectWarning("QQuickShaderEffect: Missing reference to \'qt_Vertex\'."); + if ((presenceFlags & TexCoordPresent) == 0) + expectWarning("QQuickShaderEffect: Missing reference to \'qt_MultiTexCoord0\'."); + if ((presenceFlags & MatrixPresent) == 0) + expectWarning("QQuickShaderEffect: Missing reference to \'qt_Matrix\'."); + if ((presenceFlags & OpacityPresent) == 0) + expectWarning("QQuickShaderEffect: Missing reference to \'qt_Opacity\'."); + + static_cast(item).classBegin(); + item.setVertexShader(vertexShader); + item.setFragmentShader(fragmentShader); + static_cast(item).componentComplete(); + uninstallMsgHandler(); + + // If the uniform was successfully parsed, the notify signal has been connected to an update slot. + QCOMPARE(item.isConnected(SIGNAL(dummyChanged())), (presenceFlags & PropertyPresent) != 0); +} + +QTEST_MAIN(tst_qquickshadereffect) + +#include "tst_qquickshadereffect.moc"