aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2012-03-23 18:14:29 +0100
committerQt by Nokia <qt-info@nokia.com>2012-04-16 09:25:06 +0200
commite5f45d9b57bb0542ec47e5a8a4e57388b6d59d35 (patch)
tree039622ca4f22c5be93cd491d506fe49427ae9672 /src
parent31c5b237c4f0eb6848c7d2e3ae84232c6f8f6d26 (diff)
Add QJson support to QV8Engine
Make QV8Engine perform direct conversion between JavaScript values and QJson{Value,Object,Array}. This implementation always makes a deep clone of the QJson{Object,Array} when converting to JS; it might make sense to add a lazy conversion scheme for dealing with large objects. Change-Id: Id0b65891a19515ce22f1e51fa8a28d9f3e595271 Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com> Reviewed-by: Jamey Hicks <jamey.hicks@nokia.com> Reviewed-by: Lars Knoll <lars.knoll@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/v8/qv8engine.cpp67
-rw-r--r--src/qml/qml/v8/qv8engine_p.h9
-rw-r--r--src/qml/qml/v8/qv8jsonwrapper.cpp183
-rw-r--r--src/qml/qml/v8/qv8jsonwrapper_p.h93
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp3
-rw-r--r--src/qml/qml/v8/v8.pri2
6 files changed, 357 insertions, 0 deletions
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index 2302d0e369..8444d657ec 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -58,6 +58,9 @@
#include "qv8domerrors_p.h"
#include "qv8sqlerrors_p.h"
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
Q_DECLARE_METATYPE(QJSValue)
Q_DECLARE_METATYPE(QList<int>)
@@ -155,6 +158,7 @@ QV8Engine::QV8Engine(QJSEngine* qq, QJSEngine::ContextOwnership ownership)
m_variantWrapper.init(this);
m_valueTypeWrapper.init(this);
m_sequenceWrapper.init(this);
+ m_jsonWrapper.init(this);
{
v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
@@ -182,6 +186,7 @@ QV8Engine::~QV8Engine()
qPersistentDispose(m_strongReferencer);
+ m_jsonWrapper.destroy();
m_sequenceWrapper.destroy();
m_valueTypeWrapper.destroy();
m_variantWrapper.destroy();
@@ -220,6 +225,9 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
if (typeHint == QVariant::Bool)
return QVariant(value->BooleanValue());
+ if (typeHint == QMetaType::QJsonValue)
+ return QVariant::fromValue(jsonValueFromJS(value));
+
if (value->IsObject()) {
QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
if (r) {
@@ -251,6 +259,9 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
case QV8ObjectResource::SequenceType:
return m_sequenceWrapper.toVariant(r);
}
+ } else if (typeHint == QMetaType::QJsonObject
+ && !value->IsArray() && !value->IsFunction()) {
+ return QVariant::fromValue(jsonObjectFromJS(value));
}
}
@@ -269,6 +280,8 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
}
return qVariantFromValue<QList<QObject*> >(list);
+ } else if (typeHint == QMetaType::QJsonArray) {
+ return QVariant::fromValue(jsonArrayFromJS(value));
}
bool succeeded = false;
@@ -368,6 +381,12 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
case QMetaType::QVariantMap:
return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
+ case QMetaType::QJsonValue:
+ return jsonValueToJS(*reinterpret_cast<const QJsonValue *>(ptr));
+ case QMetaType::QJsonObject:
+ return jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(ptr));
+ case QMetaType::QJsonArray:
+ return jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(ptr));
default:
break;
@@ -1152,6 +1171,15 @@ v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data)
case QMetaType::QVariant:
result = variantToJS(*reinterpret_cast<const QVariant*>(data));
break;
+ case QMetaType::QJsonValue:
+ result = jsonValueToJS(*reinterpret_cast<const QJsonValue *>(data));
+ break;
+ case QMetaType::QJsonObject:
+ result = jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(data));
+ break;
+ case QMetaType::QJsonArray:
+ result = jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(data));
+ break;
default:
if (type == qMetaTypeId<QJSValue>()) {
return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->asV8Value(this);
@@ -1267,6 +1295,15 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data
case QMetaType::QVariant:
*reinterpret_cast<QVariant*>(data) = variantFromJS(value);
return true;
+ case QMetaType::QJsonValue:
+ *reinterpret_cast<QJsonValue *>(data) = jsonValueFromJS(value);
+ return true;
+ case QMetaType::QJsonObject:
+ *reinterpret_cast<QJsonObject *>(data) = jsonObjectFromJS(value);
+ return true;
+ case QMetaType::QJsonArray:
+ *reinterpret_cast<QJsonArray *>(data) = jsonArrayFromJS(value);
+ return true;
default:
;
}
@@ -1383,6 +1420,36 @@ QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value)
return variantMapFromJS(value->ToObject());
}
+v8::Handle<v8::Value> QV8Engine::jsonValueToJS(const QJsonValue &value)
+{
+ return m_jsonWrapper.fromJsonValue(value);
+}
+
+QJsonValue QV8Engine::jsonValueFromJS(v8::Handle<v8::Value> value)
+{
+ return m_jsonWrapper.toJsonValue(value);
+}
+
+v8::Local<v8::Object> QV8Engine::jsonObjectToJS(const QJsonObject &object)
+{
+ return m_jsonWrapper.fromJsonObject(object);
+}
+
+QJsonObject QV8Engine::jsonObjectFromJS(v8::Handle<v8::Value> value)
+{
+ return m_jsonWrapper.toJsonObject(value);
+}
+
+v8::Local<v8::Array> QV8Engine::jsonArrayToJS(const QJsonArray &array)
+{
+ return m_jsonWrapper.fromJsonArray(array);
+}
+
+QJsonArray QV8Engine::jsonArrayFromJS(v8::Handle<v8::Value> value)
+{
+ return m_jsonWrapper.toJsonArray(value);
+}
+
bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value,
const QByteArray &targetType,
void **result)
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index 2eb3668501..1fc03d82e5 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -80,6 +80,7 @@
#include "qv8variantwrapper_p.h"
#include "qv8valuetypewrapper_p.h"
#include "qv8sequencewrapper_p.h"
+#include "qv8jsonwrapper_p.h"
QT_BEGIN_NAMESPACE
@@ -415,6 +416,13 @@ public:
v8::Handle<v8::Value> variantToJS(const QVariant &value);
QVariant variantFromJS(v8::Handle<v8::Value> value);
+ v8::Handle<v8::Value> jsonValueToJS(const QJsonValue &value);
+ QJsonValue jsonValueFromJS(v8::Handle<v8::Value> value);
+ v8::Local<v8::Object> jsonObjectToJS(const QJsonObject &object);
+ QJsonObject jsonObjectFromJS(v8::Handle<v8::Value> value);
+ v8::Local<v8::Array> jsonArrayToJS(const QJsonArray &array);
+ QJsonArray jsonArrayFromJS(v8::Handle<v8::Value> value);
+
v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
@@ -477,6 +485,7 @@ protected:
QV8VariantWrapper m_variantWrapper;
QV8ValueTypeWrapper m_valueTypeWrapper;
QV8SequenceWrapper m_sequenceWrapper;
+ QV8JsonWrapper m_jsonWrapper;
v8::Persistent<v8::Function> m_getOwnPropertyNames;
v8::Persistent<v8::Function> m_freezeObject;
diff --git a/src/qml/qml/v8/qv8jsonwrapper.cpp b/src/qml/qml/v8/qv8jsonwrapper.cpp
new file mode 100644
index 0000000000..ff8cc4faba
--- /dev/null
+++ b/src/qml/qml/v8/qv8jsonwrapper.cpp
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module 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 "qv8jsonwrapper_p.h"
+#include "qv8engine_p.h"
+#include "qjsconverter_impl_p.h"
+
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+QV8JsonWrapper::QV8JsonWrapper()
+: m_engine(0)
+{
+}
+
+QV8JsonWrapper::~QV8JsonWrapper()
+{
+}
+
+void QV8JsonWrapper::init(QV8Engine *engine)
+{
+ m_engine = engine;
+}
+
+void QV8JsonWrapper::destroy()
+{
+}
+
+v8::Handle<v8::Value> QV8JsonWrapper::fromJsonValue(const QJsonValue &value)
+{
+ if (value.isString())
+ return QJSConverter::toString(value.toString());
+ else if (value.isDouble())
+ return v8::Number::New(value.toDouble());
+ else if (value.isBool())
+ return value.toBool() ? v8::True() : v8::False();
+ else if (value.isArray())
+ return fromJsonArray(value.toArray());
+ else if (value.isObject())
+ return fromJsonObject(value.toObject());
+ else if (value.isNull())
+ return v8::Null();
+ else
+ return v8::Undefined();
+}
+
+QJsonValue QV8JsonWrapper::toJsonValue(v8::Handle<v8::Value> value)
+{
+ if (value->IsString())
+ return QJsonValue(QJSConverter::toString(value.As<v8::String>()));
+ else if (value->IsNumber())
+ return QJsonValue(value->NumberValue());
+ else if (value->IsBoolean())
+ return QJsonValue(value->BooleanValue());
+ else if (value->IsArray())
+ return toJsonArray(value.As<v8::Array>());
+ else if (value->IsObject())
+ return toJsonObject(value.As<v8::Object>());
+ else if (value->IsNull())
+ return QJsonValue(QJsonValue::Null);
+ else
+ return QJsonValue(QJsonValue::Undefined);
+}
+
+v8::Local<v8::Object> QV8JsonWrapper::fromJsonObject(const QJsonObject &object)
+{
+ v8::Local<v8::Object> v8object = v8::Object::New();
+ for (QJsonObject::const_iterator it = object.begin(); it != object.end(); ++it)
+ v8object->Set(QJSConverter::toString(it.key()), fromJsonValue(it.value()));
+ return v8object;
+}
+
+QJsonObject QV8JsonWrapper::toJsonObject(v8::Handle<v8::Value> value)
+{
+ QJsonObject result;
+ if (!value->IsObject() || value->IsArray() || value->IsFunction())
+ return result;
+
+ v8::Handle<v8::Object> v8object(value.As<v8::Object>());
+ int hash = v8object->GetIdentityHash();
+ if (m_visitedConversionObjects.contains(hash)) {
+ // Avoid recursion.
+ // For compatibility with QVariant{List,Map} conversion, we return an
+ // empty object (and no error is thrown).
+ return result;
+ }
+
+ m_visitedConversionObjects.insert(hash);
+
+ v8::Local<v8::Array> propertyNames = m_engine->getOwnPropertyNames(v8object);
+ uint32_t length = propertyNames->Length();
+ for (uint32_t i = 0; i < length; ++i) {
+ v8::Local<v8::Value> name = propertyNames->Get(i);
+ v8::Local<v8::Value> propertyValue = v8object->Get(name);
+ if (!propertyValue->IsFunction())
+ result.insert(QJSConverter::toString(name->ToString()), toJsonValue(propertyValue));
+ }
+
+ m_visitedConversionObjects.remove(hash);
+
+ return result;
+}
+
+v8::Local<v8::Array> QV8JsonWrapper::fromJsonArray(const QJsonArray &array)
+{
+ int size = array.size();
+ v8::Local<v8::Array> v8array = v8::Array::New(size);
+ for (int i = 0; i < size; i++)
+ v8array->Set(i, fromJsonValue(array.at(i)));
+ return v8array;
+}
+
+QJsonArray QV8JsonWrapper::toJsonArray(v8::Handle<v8::Value> value)
+{
+ QJsonArray result;
+ if (!value->IsArray())
+ return result;
+
+ v8::Handle<v8::Array> v8array(value.As<v8::Array>());
+ int hash = v8array->GetIdentityHash();
+ if (m_visitedConversionObjects.contains(hash)) {
+ // Avoid recursion.
+ // For compatibility with QVariant{List,Map} conversion, we return an
+ // empty array (and no error is thrown).
+ return result;
+ }
+
+ m_visitedConversionObjects.insert(hash);
+
+ uint32_t length = v8array->Length();
+ for (uint32_t i = 0; i < length; ++i) {
+ v8::Local<v8::Value> element = v8array->Get(i);
+ if (!element->IsFunction())
+ result.append(toJsonValue(element));
+ }
+
+ m_visitedConversionObjects.remove(hash);
+
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8jsonwrapper_p.h b/src/qml/qml/v8/qv8jsonwrapper_p.h
new file mode 100644
index 0000000000..842a3aa5d5
--- /dev/null
+++ b/src/qml/qml/v8/qv8jsonwrapper_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module 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$
+**
+****************************************************************************/
+
+#ifndef QV8JSONWRAPPER_P_H
+#define QV8JSONWRAPPER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qset.h>
+#include <private/qv8_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QJsonValue;
+class QJsonObject;
+class QJsonArray;
+
+class QV8Engine;
+class QV8JsonWrapper
+{
+public:
+ QV8JsonWrapper();
+ ~QV8JsonWrapper();
+
+ void init(QV8Engine *);
+ void destroy();
+
+ v8::Handle<v8::Value> fromJsonValue(const QJsonValue &value);
+ QJsonValue toJsonValue(v8::Handle<v8::Value> value);
+
+ v8::Local<v8::Object> fromJsonObject(const QJsonObject &object);
+ QJsonObject toJsonObject(v8::Handle<v8::Value> value);
+
+ v8::Local<v8::Array> fromJsonArray(const QJsonArray &array);
+ QJsonArray toJsonArray(v8::Handle<v8::Value> value);
+
+private:
+ QV8Engine *m_engine;
+ QSet<int> m_visitedConversionObjects;
+};
+
+QT_END_NAMESPACE
+
+#endif // QV8JSONWRAPPER_P_H
+
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index ce85725642..9a5aaca6e4 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -54,6 +54,7 @@
#include <private/qqmlexpression_p.h>
#include <QtQml/qjsvalue.h>
+#include <QtCore/qjsonvalue.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qtimer.h>
#include <QtCore/qatomic.h>
@@ -659,6 +660,8 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
} else if (value->IsUndefined() && property->propType == qMetaTypeId<QVariant>()) {
PROPERTY_STORE(QVariant, QVariant());
+ } else if (value->IsUndefined() && property->propType == QMetaType::QJsonValue) {
+ PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
} else if (value->IsUndefined()) {
QString error = QLatin1String("Cannot assign [undefined] to ") +
QLatin1String(QMetaType::typeName(property->propType));
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
index 7816c84b79..52b6bf480a 100644
--- a/src/qml/qml/v8/v8.pri
+++ b/src/qml/qml/v8/v8.pri
@@ -15,6 +15,7 @@ HEADERS += \
$$PWD/qv8variantwrapper_p.h \
$$PWD/qv8variantresource_p.h \
$$PWD/qv8valuetypewrapper_p.h \
+ $$PWD/qv8jsonwrapper_p.h \
$$PWD/qv8include_p.h \
$$PWD/qv8worker_p.h \
$$PWD/qv8bindings_p.h \
@@ -33,6 +34,7 @@ SOURCES += \
$$PWD/qv8listwrapper.cpp \
$$PWD/qv8variantwrapper.cpp \
$$PWD/qv8valuetypewrapper.cpp \
+ $$PWD/qv8jsonwrapper.cpp \
$$PWD/qv8include.cpp \
$$PWD/qv8worker.cpp \
$$PWD/qv8bindings.cpp \