diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-09-10 17:13:10 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@digia.com> | 2014-09-17 08:13:11 +0200 |
commit | 3dbe05f6bf3fd51ce8097c35f6c7f12b39acb0f6 (patch) | |
tree | 444ed433aa02085357b589b19b28f4bc1c243320 /src/qml/jsapi | |
parent | cfe1a8152c948a4586ffa1fe79b47f9a0e88beb5 (diff) |
Fix mapping of JS objects/arrays to C++
[ChangeLog][QtQml][Important Behavior Changes] When a JavaScript object/array
is passed to C++ through a QVariant, the engine no longer immediately converts
the object recursively into a QVariantMap or QVariantList but instead stores
a QJSValue in the QVariant. This prevents a loss of data when the JS object
contains non-primitive types such as function objects for example. Code that
expects the variant type to be exactly QVariant::Map or QVariant::List may
need to be adapted. Registered conversion functions however ensure that code
that merely calls toMap() or toList() continues to work.
Task-number: QTBUG-40431
Change-Id: I1dbc1d5f8e78ad28bb62db3681b9a0b34557e7f5
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/jsapi')
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 27 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue.cpp | 69 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue_p.h | 7 |
3 files changed, 72 insertions, 31 deletions
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 58251fac96..0d2b394cd6 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -420,17 +420,19 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) QV4::ScopedValue v(scope, vp->getValue(engine->m_v4Engine)); return engine->metaTypeFromJS(v, type, ptr); } else if (vp->value.isEmpty()) { - // have a string based value without engine. Do conversion manually - if (type == QMetaType::Bool) { - *reinterpret_cast<bool*>(ptr) = vp->string.length() != 0; - return true; - } - if (type == QMetaType::QString) { - *reinterpret_cast<QString*>(ptr) = vp->string; - return true; - } - double d = QV4::RuntimeHelpers::stringToNumber(vp->string); - switch (type) { + if (vp->unboundData.userType() == QMetaType::QString) { + QString string = vp->unboundData.toString(); + // have a string based value without engine. Do conversion manually + if (type == QMetaType::Bool) { + *reinterpret_cast<bool*>(ptr) = string.length() != 0; + return true; + } + if (type == QMetaType::QString) { + *reinterpret_cast<QString*>(ptr) = string; + return true; + } + double d = QV4::RuntimeHelpers::stringToNumber(string); + switch (type) { case QMetaType::Int: *reinterpret_cast<int*>(ptr) = QV4::Primitive::toInt32(d); return true; @@ -466,6 +468,9 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) return true; default: return false; + } + } else { + return QMetaType::convert(&vp->unboundData.data_ptr(), vp->unboundData.userType(), ptr, type); } } else { switch (type) { diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index 891f17762c..47a764e641 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -58,14 +58,14 @@ QV4::ReturnedValue QJSValuePrivate::getValue(QV4::ExecutionEngine *e) } if (value.isEmpty()) { - value = QV4::Encode(engine->newString(string)); + value = QV4::Encode(engine->v8Engine->fromVariant(unboundData)); PersistentValuePrivate **listRoot = &engine->memoryManager->m_persistentValues; prev = listRoot; next = *listRoot; *prev = this; if (next) next->prev = &this->next; - string = QString(); + unboundData.clear(); } return value.asReturnedValue(); } @@ -353,8 +353,21 @@ bool QJSValue::isVariant() const */ QString QJSValue::toString() const { - if (d->value.isEmpty()) - return d->string; + if (d->value.isEmpty()) { + if (d->unboundData.type() == QVariant::Map) + return QStringLiteral("[object Object]"); + else if (d->unboundData.type() == QVariant::List) { + const QVariantList list = d->unboundData.toList(); + QString result; + for (int i = 0; i < list.count(); ++i) { + if (i > 0) + result.append(QLatin1Char(',')); + result.append(list.at(i).toString()); + } + return result; + } + return d->unboundData.toString(); + } return d->value.toQStringNoThrow(); } @@ -372,8 +385,14 @@ QString QJSValue::toString() const */ double QJSValue::toNumber() const { - if (d->value.isEmpty()) - return RuntimeHelpers::stringToNumber(d->string); + if (d->value.isEmpty()) { + if (d->unboundData.type() == QVariant::String) + return RuntimeHelpers::stringToNumber(d->unboundData.toString()); + else if (d->unboundData.canConvert<double>()) + return d->unboundData.value<double>(); + else + return std::numeric_limits<double>::quiet_NaN(); + } QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; double dbl = d->value.toNumber(); @@ -398,8 +417,12 @@ double QJSValue::toNumber() const */ bool QJSValue::toBool() const { - if (d->value.isEmpty()) - return d->string.length() > 0; + if (d->value.isEmpty()) { + if (d->unboundData.userType() == QMetaType::QString) + return d->unboundData.toString().length() > 0; + else + return d->unboundData.toBool(); + } QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; bool b = d->value.toBoolean(); @@ -424,8 +447,12 @@ bool QJSValue::toBool() const */ qint32 QJSValue::toInt() const { - if (d->value.isEmpty()) - return QV4::Primitive::toInt32(RuntimeHelpers::stringToNumber(d->string)); + if (d->value.isEmpty()) { + if (d->unboundData.userType() == QMetaType::QString) + return QV4::Primitive::toInt32(RuntimeHelpers::stringToNumber(d->unboundData.toString())); + else + return d->unboundData.toInt(); + } QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; qint32 i = d->value.toInt32(); @@ -450,8 +477,12 @@ qint32 QJSValue::toInt() const */ quint32 QJSValue::toUInt() const { - if (d->value.isEmpty()) - return QV4::Primitive::toUInt32(RuntimeHelpers::stringToNumber(d->string)); + if (d->value.isEmpty()) { + if (d->unboundData.userType() == QMetaType::QString) + return QV4::Primitive::toUInt32(RuntimeHelpers::stringToNumber(d->unboundData.toString())); + else + return d->unboundData.toUInt(); + } QV4::ExecutionContext *ctx = d->engine ? d->engine->currentContext() : 0; quint32 u = d->value.toUInt32(); @@ -487,7 +518,7 @@ quint32 QJSValue::toUInt() const QVariant QJSValue::toVariant() const { if (d->value.isEmpty()) - return QVariant(d->string); + return d->unboundData; return QV4::VariantObject::toVariant(d->value); } @@ -775,8 +806,10 @@ bool QJSValue::equals(const QJSValue& other) const { if (d->value.isEmpty()) { if (other.d->value.isEmpty()) - return d->string == other.d->string; - return js_equal(d->string, QV4::ValueRef(other.d->value)); + return d->unboundData == other.d->unboundData; + if (d->unboundData.type() == QVariant::Map || d->unboundData.type() == QVariant::List) + return false; + return js_equal(d->unboundData.toString(), QV4::ValueRef(other.d->value)); } if (other.d->value.isEmpty()) return other.equals(*this); @@ -810,9 +843,11 @@ bool QJSValue::strictlyEquals(const QJSValue& other) const { if (d->value.isEmpty()) { if (other.d->value.isEmpty()) - return d->string == other.d->string; + return d->unboundData == other.d->unboundData; + if (d->unboundData.type() == QVariant::Map || d->unboundData.type() == QVariant::List) + return false; if (other.d->value.isString()) - return d->string == other.d->value.stringValue()->toQString(); + return d->unboundData.toString() == other.d->value.stringValue()->toQString(); return false; } if (other.d->value.isEmpty()) diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h index e66c1bcde4..43a3a74e38 100644 --- a/src/qml/jsapi/qjsvalue_p.h +++ b/src/qml/jsapi/qjsvalue_p.h @@ -51,6 +51,7 @@ #include <private/qv4string_p.h> #include <private/qv4engine_p.h> #include <private/qv4object_p.h> +#include <private/qflagpointer_p.h> QT_BEGIN_NAMESPACE @@ -72,8 +73,8 @@ public: Q_ASSERT(!value.isEmpty()); } QJSValuePrivate(const QString &s) - : PersistentValuePrivate(QV4::Primitive::emptyValue().asReturnedValue()) - , string(s) + : PersistentValuePrivate(QV4::Primitive::emptyValue().asReturnedValue()), + unboundData(s) { } @@ -81,7 +82,7 @@ public: static QJSValuePrivate *get(const QJSValue &v) { return v.d; } - QString string; + QVariant unboundData; }; QT_END_NAMESPACE |