diff options
11 files changed, 171 insertions, 1 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c28df7d74a..317eb7a8a7 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1250,7 +1250,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return ld->d()->locale; if (const QV4::DateObject *d = value.as<DateObject>()) return d->toQDateTime(); - if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) + if (const ArrayBuffer *d = value.as<ArrayBuffer>()) return d->asByteArray(); // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)! @@ -1378,6 +1378,8 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) return QV4::Encode(*reinterpret_cast<const double*>(ptr)); case QMetaType::QString: return newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue(); + case QMetaType::QByteArray: + return newArrayBuffer(*reinterpret_cast<const QByteArray*>(ptr))->asReturnedValue(); case QMetaType::Float: return QV4::Encode(*reinterpret_cast<const float*>(ptr)); case QMetaType::Short: @@ -1554,6 +1556,8 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return QV4::Encode(*reinterpret_cast<const double*>(data)); case QMetaType::QString: return newString(*reinterpret_cast<const QString*>(data))->asReturnedValue(); + case QMetaType::QByteArray: + return newArrayBuffer(*reinterpret_cast<const QByteArray*>(data))->asReturnedValue(); case QMetaType::Float: return QV4::Encode(*reinterpret_cast<const float*>(data)); case QMetaType::Short: @@ -1646,6 +1650,12 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) else *reinterpret_cast<QString*>(data) = value->toQString(); return true; + case QMetaType::QByteArray: + if (const ArrayBuffer *ab = value->as<ArrayBuffer>()) + *reinterpret_cast<QByteArray*>(data) = ab->asByteArray(); + else + *reinterpret_cast<QByteArray*>(data) = QByteArray(); + return true; case QMetaType::Float: *reinterpret_cast<float*>(data) = value->toNumber(); return true; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index f529b4bc7d..596a97a444 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -54,6 +54,7 @@ #include <private/qqmlbuiltinfunctions_p.h> #include <private/qv8engine_p.h> +#include <private/qv4arraybuffer_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4runtime_p.h> #include <private/qv4variantobject_p.h> @@ -1101,6 +1102,7 @@ private: // Pointers to allocData union { QString *qstringPtr; + QByteArray *qbyteArrayPtr; QVariant *qvariantPtr; QList<QObject *> *qlistPtr; QJSValue *qjsValuePtr; @@ -1222,6 +1224,13 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } + } else if (actual.as<ArrayBuffer>()) { + switch (conversionType) { + case QMetaType::QByteArray: + return 0; + default: + return 10; + } } else if (actual.as<ArrayObject>()) { switch (conversionType) { case QMetaType::QJsonArray: @@ -1478,6 +1487,8 @@ void CallArgument::cleanup() { if (type == QMetaType::QString) { qstringPtr->~QString(); + } else if (type == QMetaType::QByteArray) { + qbyteArrayPtr->~QByteArray(); } else if (type == -1 || type == QMetaType::QVariant) { qvariantPtr->~QVariant(); } else if (type == qMetaTypeId<QJSValue>()) { @@ -1580,6 +1591,12 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q else qstringPtr = new (&allocData) QString(value.toQStringNoThrow()); type = callType; + } else if (callType == QMetaType::QByteArray) { + if (const ArrayBuffer *ab = value.as<ArrayBuffer>()) + qbyteArrayPtr = new (&allocData) QByteArray(ab->asByteArray()); + else + qbyteArrayPtr = new (&allocData) QByteArray(); + type = callType; } else if (callType == QMetaType::QObjectStar) { qobjectPtr = 0; if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) @@ -1677,6 +1694,8 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine) return QV4::Encode(floatValue); } else if (type == QMetaType::QString) { return QV4::Encode(engine->newString(*qstringPtr)); + } else if (type == QMetaType::QByteArray) { + return QV4::Encode(engine->newArrayBuffer(*qbyteArrayPtr)); } else if (type == QMetaType::QObjectStar) { QObject *object = qobjectPtr; if (object) diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml new file mode 100644 index 0000000000..b64a2e23c0 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_arg.qml @@ -0,0 +1,11 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: { + var data = new Uint8Array([1, 2, 3]); + var sum = byteArrayMethod_Sum(data.buffer); + ok = sum == 6; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml new file mode 100644 index 0000000000..9e1c91810a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_overload.qml @@ -0,0 +1,7 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: ok = byteArrayMethod_Overloaded(new ArrayBuffer()); +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml new file mode 100644 index 0000000000..5a4f9fec0b --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_method_return.qml @@ -0,0 +1,15 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + Component.onCompleted: { + var buf = byteArrayMethod_CountUp(1, 3); + var view = new DataView(buf); + ok = buf instanceof ArrayBuffer + && buf.byteLength == 3 + && view.getUint8(0) == 1 + && view.getUint8(1) == 2 + && view.getUint8(2) == 3; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml new file mode 100644 index 0000000000..78ebb1abe1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_get.qml @@ -0,0 +1,5 @@ +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: byteArrayProperty instanceof ArrayBuffer +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml new file mode 100644 index 0000000000..e8a51273ca --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_property_set.qml @@ -0,0 +1,11 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + onByteArraySignal: ok = byteArrayProperty instanceof ArrayBuffer + Component.onCompleted: { + byteArrayProperty = new ArrayBuffer(42); + ok = byteArrayProperty instanceof ArrayBuffer && byteArrayProperty.byteLength == 42; + } +} diff --git a/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml b/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml new file mode 100644 index 0000000000..d9f436e788 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/arraybuffer_signal_arg.qml @@ -0,0 +1,14 @@ +import QtQuick 2.7 +import Test 1.0 + +MyArrayBufferTestClass { + property bool ok: false + onByteArraySignal: { + var view = new DataView(arg); + ok = arg instanceof ArrayBuffer + && arg.byteLength == 2 + && view.getUint8(0) == 42 + && view.getUint8(1) == 43; + } + Component.onCompleted: emitByteArraySignal(42, 2) +} diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index 9593bfc940..cc39422dce 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -98,6 +98,8 @@ void registerTypes() qmlRegisterType<MyCompositeBaseType>("Test", 1, 0, "MyCompositeBaseType"); qmlRegisterSingletonType<MyTypeObjectSingleton>("Test", 1, 0, "MyTypeObjectSingleton", myTypeObjectSingleton); + + qmlRegisterType<MyArrayBufferTestClass>("Test", 1, 0, "MyArrayBufferTestClass"); } QVariant myCustomVariantTypeConverter(const QString &data) diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 082182e8e6..2344b6a03b 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1090,6 +1090,58 @@ public: static QObject *qmlAttachedProperties(QObject *parent) { return new QObject(parent); } }; +class MyArrayBufferTestClass : public QObject +{ + Q_OBJECT + Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty NOTIFY byteArrayPropertyChanged) + +signals: + void byteArrayPropertyChanged(); + void byteArraySignal(QByteArray arg); + +public: + QByteArray byteArrayPropertyValue; + QByteArray byteArrayProperty() const { + return byteArrayPropertyValue; + } + void setByteArrayProperty(const QByteArray &v) { + byteArrayPropertyValue = v; + emit byteArrayPropertyChanged(); + } + Q_INVOKABLE void emitByteArraySignal(char begin, char num) { + byteArraySignal(byteArrayMethod_CountUp(begin, num)); + } + Q_INVOKABLE int byteArrayMethod_Sum(QByteArray arg) { + int sum = 0; + for (int i = 0; i < arg.size(); ++i) { + sum += arg[i]; + } + return sum; + } + Q_INVOKABLE QByteArray byteArrayMethod_CountUp(char begin, int num) { + QByteArray ret; + for (int i = 0; i < num; ++i) { + ret.push_back(begin++); + } + return ret; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QByteArray) { + return true; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(int) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QString) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QJSValue) { + return false; + } + Q_INVOKABLE bool byteArrayMethod_Overloaded(QVariant) { + return false; + } +}; + Q_DECLARE_METATYPE(MyEnum2Class::EnumB) Q_DECLARE_METATYPE(MyEnum1Class::EnumA) Q_DECLARE_METATYPE(Qt::TextFormat) diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index c74b4dd1f1..dd7410dfd3 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -250,6 +250,9 @@ private slots: void deleteSingletons(); + void arrayBuffer_data(); + void arrayBuffer(); + private: QQmlEngine engine; QStringList defaultImportPathList; @@ -4145,6 +4148,27 @@ void tst_qqmllanguage::deleteSingletons() QVERIFY(singleton.data() == 0); } +void tst_qqmllanguage::arrayBuffer_data() +{ + QTest::addColumn<QString>("file"); + QTest::newRow("arraybuffer_property_get") << "arraybuffer_property_get.qml"; + QTest::newRow("arraybuffer_property_set") << "arraybuffer_property_set.qml"; + QTest::newRow("arraybuffer_signal_arg") << "arraybuffer_signal_arg.qml"; + QTest::newRow("arraybuffer_method_arg") << "arraybuffer_method_arg.qml"; + QTest::newRow("arraybuffer_method_return") << "arraybuffer_method_return.qml"; + QTest::newRow("arraybuffer_method_overload") << "arraybuffer_method_overload.qml"; +} + +void tst_qqmllanguage::arrayBuffer() +{ + QFETCH(QString, file); + QQmlComponent component(&engine, testFile(file)); + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("ok").toBool(), true); +} + QTEST_MAIN(tst_qqmllanguage) #include "tst_qqmllanguage.moc" |