From c0f07d5707180856bb2705359d780a836653188c Mon Sep 17 00:00:00 2001 From: Kent Hansen Date: Tue, 24 Apr 2012 18:22:06 +0200 Subject: [PATCH] Specialize for QJson types in the QObject meta-call binding Avoid falling back to QVariant conversion; make the overload handling consistent. Also make the MaxSizeOf template helper class actually compute the correct size needed for the argument storage. Change-Id: I04afb378bd89743d542973cc3bb0ceb729b400d9 Reviewed-by: Lars Knoll --- src/qml/qml/v8/qv8qobjectwrapper.cpp | 62 +++++++++++++-- tests/auto/qml/qqmlecmascript/testtypes.h | 11 +++ .../auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 91 ++++++++++++++++++++++ 3 files changed, 158 insertions(+), 6 deletions(-) diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp index 176d4fb..70f10b2 100644 --- a/src/qml/qml/v8/qv8qobjectwrapper.cpp +++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp @@ -54,6 +54,8 @@ #include #include +#include +#include #include #include #include @@ -124,14 +126,15 @@ public: namespace { -template -class MaxSizeOf5 { +template +class MaxSizeOf8 { template struct SMax { - static const size_t Size = sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X); + char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)]; }; public: - static const size_t Size = SMax > > >::Size; + static const size_t Size = sizeof(SMax > > > > > >); }; struct CallArgument { @@ -155,11 +158,14 @@ private: bool boolValue; QObject *qobjectPtr; - char allocData[MaxSizeOf5, QJSValue, - QQmlV8Handle>::Size]; + QQmlV8Handle, + QJsonArray, + QJsonObject, + QJsonValue>::Size]; qint64 q_for_alignment; }; @@ -170,6 +176,9 @@ private: QList *qlistPtr; QJSValue *qjsValuePtr; QQmlV8Handle *handlePtr; + QJsonArray *jsonArrayPtr; + QJsonObject *jsonObjectPtr; + QJsonValue *jsonValuePtr; }; int type; @@ -1588,6 +1597,8 @@ static int MatchScore(v8::Handle actual, int conversionType) case QMetaType::Char: case QMetaType::UChar: return 6; + case QMetaType::QJsonValue: + return 5; default: return 10; } @@ -1595,6 +1606,8 @@ static int MatchScore(v8::Handle actual, int conversionType) switch (conversionType) { case QMetaType::QString: return 0; + case QMetaType::QJsonValue: + return 5; default: return 10; } @@ -1602,6 +1615,8 @@ static int MatchScore(v8::Handle actual, int conversionType) switch (conversionType) { case QMetaType::Bool: return 0; + case QMetaType::QJsonValue: + return 5; default: return 10; } @@ -1625,6 +1640,8 @@ static int MatchScore(v8::Handle actual, int conversionType) } } else if (actual->IsArray()) { switch (conversionType) { + case QMetaType::QJsonArray: + return 3; case QMetaType::QStringList: case QMetaType::QVariantList: return 5; @@ -1635,6 +1652,7 @@ static int MatchScore(v8::Handle actual, int conversionType) switch (conversionType) { case QMetaType::VoidStar: case QMetaType::QObjectStar: + case QMetaType::QJsonValue: return 0; default: { const char *typeName = QMetaType::typeName(conversionType); @@ -1662,6 +1680,8 @@ static int MatchScore(v8::Handle actual, int conversionType) return 0; else return 10; + } else if (conversionType == QMetaType::QJsonObject) { + return 5; } else { return 10; } @@ -1983,6 +2003,12 @@ void CallArgument::cleanup() qjsValuePtr->~QJSValue(); } else if (type == qMetaTypeId >()) { qlistPtr->~QList(); + } else if (type == QMetaType::QJsonArray) { + jsonArrayPtr->~QJsonArray(); + } else if (type == QMetaType::QJsonObject) { + jsonObjectPtr->~QJsonObject(); + } else if (type == QMetaType::QJsonValue) { + jsonValuePtr->~QJsonValue(); } } @@ -2023,6 +2049,15 @@ void CallArgument::initAsType(int callType) } else if (callType == qMetaTypeId()) { type = callType; handlePtr = new (&allocData) QQmlV8Handle; + } else if (callType == QMetaType::QJsonArray) { + type = callType; + jsonArrayPtr = new (&allocData) QJsonArray(); + } else if (callType == QMetaType::QJsonObject) { + type = callType; + jsonObjectPtr = new (&allocData) QJsonObject(); + } else if (callType == QMetaType::QJsonValue) { + type = callType; + jsonValuePtr = new (&allocData) QJsonValue(); } else if (callType == QMetaType::Void) { type = -1; qvariantPtr = new (&allocData) QVariant(); @@ -2080,6 +2115,15 @@ void CallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle()) { handlePtr = new (&allocData) QQmlV8Handle(QQmlV8Handle::fromHandle(value)); type = callType; + } else if (callType == QMetaType::QJsonArray) { + jsonArrayPtr = new (&allocData) QJsonArray(engine->jsonArrayFromJS(value)); + type = callType; + } else if (callType == QMetaType::QJsonObject) { + jsonObjectPtr = new (&allocData) QJsonObject(engine->jsonObjectFromJS(value)); + type = callType; + } else if (callType == QMetaType::QJsonValue) { + jsonValuePtr = new (&allocData) QJsonValue(engine->jsonValueFromJS(value)); + type = callType; } else if (callType == QMetaType::Void) { *qvariantPtr = QVariant(); } else { @@ -2141,6 +2185,12 @@ v8::Handle CallArgument::toValue(QV8Engine *engine) return array; } else if (type == qMetaTypeId()) { return handlePtr->toHandle(); + } else if (type == QMetaType::QJsonArray) { + return engine->jsonArrayToJS(*jsonArrayPtr); + } else if (type == QMetaType::QJsonObject) { + return engine->jsonObjectToJS(*jsonObjectPtr); + } else if (type == QMetaType::QJsonValue) { + return engine->jsonValueToJS(*jsonValuePtr); } else if (type == -1 || type == qMetaTypeId()) { QVariant value = *qvariantPtr; v8::Handle rv = engine->fromVariant(value); diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index 502c65d..f39d5d9 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -54,6 +54,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -678,6 +681,14 @@ public: Q_INVOKABLE void method_QVariant(QVariant a, QVariant b = QVariant()) { invoke(21); m_actuals << a << b; } + Q_INVOKABLE void method_QJsonObject(const QJsonObject &a) { invoke(22); m_actuals << QVariant::fromValue(a); } + Q_INVOKABLE void method_QJsonArray(const QJsonArray &a) { invoke(23); m_actuals << QVariant::fromValue(a); } + Q_INVOKABLE void method_QJsonValue(const QJsonValue &a) { invoke(24); m_actuals << QVariant::fromValue(a); } + + Q_INVOKABLE void method_overload(const QJsonObject &a) { invoke(25); m_actuals << QVariant::fromValue(a); } + Q_INVOKABLE void method_overload(const QJsonArray &a) { invoke(26); m_actuals << QVariant::fromValue(a); } + Q_INVOKABLE void method_overload(const QJsonValue &a) { invoke(27); m_actuals << QVariant::fromValue(a); } + private: friend class MyInvokableBaseObject; void invoke(int idx) { if (m_invoked != -1) m_invokedError = true; m_invoked = idx;} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index b66427e..4b913ef 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -2607,6 +2607,97 @@ void tst_qqmlecmascript::callQtInvokables() QCOMPARE(o.actuals().count(), 2); QCOMPARE(o.actuals().at(0), QVariant(QString("Hello"))); QCOMPARE(o.actuals().at(1), QVariant(QString("World"))); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonObject({foo:123})", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 22); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonDocument::fromJson("{\"foo\":123}").object()); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonArray([123])", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 23); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonDocument::fromJson("[123]").array()); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(123)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 24); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(123)); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(42.35)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 24); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(42.35)); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonValue('ciao')", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 24); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(QStringLiteral("ciao"))); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(true)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 24); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(true)); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(false)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 24); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(false)); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(null)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 24); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(QJsonValue::Null)); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_QJsonValue(undefined)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 24); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(QJsonValue::Undefined)); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_overload({foo:123})", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 25); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonDocument::fromJson("{\"foo\":123}").object()); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_overload([123])", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 26); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonDocument::fromJson("[123]").array()); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_overload(null)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 27); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(QJsonValue::Null)); + + o.reset(); + QVERIFY(EVALUATE_VALUE("object.method_overload(undefined)", v8::Undefined())); + QCOMPARE(o.error(), false); + QCOMPARE(o.invoked(), 27); + QCOMPARE(o.actuals().count(), 1); + QCOMPARE(qvariant_cast(o.actuals().at(0)), QJsonValue(QJsonValue::Undefined)); } // QTBUG-13047 (check that you can pass registered object types as args) -- 2.7.4