aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@theqtcompany.com>2014-11-14 21:53:20 +0100
committerSimon Hausmann <simon.hausmann@digia.com>2014-12-23 14:51:17 +0100
commitd641008d04475bfb1c1996e408b1408618845b6f (patch)
tree537abe3f4f6751c3a41f460546782c483a9bdc8e
parentc9adc7661a7eef4f2eefb51f02c0393be2ec3898 (diff)
Prepare method invocation in QObject bindings for gadget support
In order to support calling invokable methods in gadgets from JavaScript, the wrapper code needs to be able to operate on gadgets and not only QObject pointers. The minimal abstraction for that - QQmlGadgetOrObject - is passed through the relevant invocation methods in the wrapper for that. Change-Id: I94f939c942241f49dce4d32d05bf24822b2d331b Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp130
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h10
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp8
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h20
-rw-r--r--src/qml/qml/qqmlvaluetype_p.h2
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp2
6 files changed, 118 insertions, 54 deletions
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 04c6fc349a..7acd588b22 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -1130,7 +1130,7 @@ private:
};
}
-static QV4::ReturnedValue CallMethod(QObject *object, int index, int returnType, int argCount,
+static QV4::ReturnedValue CallMethod(const QQmlObjectOrGadget &object, int index, int returnType, int argCount,
int *argTypes, QV8Engine *engine, QV4::CallData *callArgs)
{
if (argCount > 0) {
@@ -1143,7 +1143,7 @@ static QV4::ReturnedValue CallMethod(QObject *object, int index, int returnType,
for (int ii = 0; ii < args.count(); ++ii)
argData[ii] = args[ii].dataPtr();
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
+ object.metacall(QMetaObject::InvokeMetaMethod, index, argData.data());
return args[0].toValue(engine);
@@ -1154,14 +1154,14 @@ static QV4::ReturnedValue CallMethod(QObject *object, int index, int returnType,
void *args[] = { arg.dataPtr() };
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+ object.metacall(QMetaObject::InvokeMetaMethod, index, args);
return arg.toValue(engine);
} else {
void *args[] = { 0 };
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+ object.metacall(QMetaObject::InvokeMetaMethod, index, args);
return Encode::undefined();
}
@@ -1319,22 +1319,20 @@ static inline int QMetaObject_methods(const QMetaObject *metaObject)
/*!
Returns the next related method, if one, or 0.
*/
-static const QQmlPropertyData * RelatedMethod(QObject *object,
- const QQmlPropertyData *current,
- QQmlPropertyData &dummy)
+static const QQmlPropertyData * RelatedMethod(const QQmlObjectOrGadget &object,
+ const QQmlPropertyData *current,
+ QQmlPropertyData &dummy,
+ const QQmlPropertyCache *propertyCache)
{
if (!current->isOverload())
return 0;
Q_ASSERT(!current->overrideIndexIsProperty);
- QQmlPropertyCache *cache = 0;
- if (QQmlData *ddata = QQmlData::get(object))
- cache = ddata->propertyCache;
- if (cache) {
- return cache->method(current->overrideIndex);
+ if (propertyCache) {
+ return propertyCache->method(current->overrideIndex);
} else {
- const QMetaObject *mo = object->metaObject();
+ const QMetaObject *mo = object.metaObject();
int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
while (methodOffset > current->overrideIndex) {
@@ -1365,12 +1363,12 @@ static const QQmlPropertyData * RelatedMethod(QObject *object,
}
}
-static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &data,
+static QV4::ReturnedValue CallPrecise(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
QV8Engine *engine, QV4::CallData *callArgs)
{
QByteArray unknownTypeError;
- int returnType = QQmlMetaObject(object).methodReturnType(data, &unknownTypeError);
+ int returnType = object.methodReturnType(data, &unknownTypeError);
if (returnType == QMetaType::UnknownType) {
QString typeName = QString::fromLatin1(unknownTypeError);
@@ -1383,7 +1381,7 @@ static QV4::ReturnedValue CallPrecise(QObject *object, const QQmlPropertyData &d
int *args = 0;
QVarLengthArray<int, 9> dummy;
- args = QQmlMetaObject(object).methodParameterTypes(data.coreIndex, dummy, &unknownTypeError);
+ args = object.methodParameterTypes(data.coreIndex, dummy, &unknownTypeError);
if (!args) {
QString typeName = QString::fromLatin1(unknownTypeError);
@@ -1418,8 +1416,8 @@ Resolve the overloaded method to call. The algorithm works conceptually like th
If two or more overloads have the same match score, call the last one. The match
score is constructed by adding the matchScore() result for each of the parameters.
*/
-static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData &data,
- QV8Engine *engine, QV4::CallData *callArgs)
+static QV4::ReturnedValue CallOverloaded(const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
+ QV8Engine *engine, QV4::CallData *callArgs, const QQmlPropertyCache *propertyCache)
{
int argumentCount = callArgs->argc;
@@ -1438,7 +1436,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
int methodArgumentCount = 0;
int *methodArgTypes = 0;
if (attempt->hasArguments()) {
- int *args = QQmlMetaObject(object).methodParameterTypes(attempt->coreIndex, dummy, 0);
+ int *args = object.methodParameterTypes(attempt->coreIndex, dummy, 0);
if (!args) // Must be an unknown argument
continue;
@@ -1466,7 +1464,7 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
if (bestParameterScore == 0 && bestMatchScore == 0)
break; // We can't get better than that
- } while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
+ } while ((attempt = RelatedMethod(object, attempt, dummy, propertyCache)) != 0);
if (best.isValid()) {
return CallPrecise(object, best, engine, callArgs);
@@ -1475,8 +1473,8 @@ static QV4::ReturnedValue CallOverloaded(QObject *object, const QQmlPropertyData
const QQmlPropertyData *candidate = &data;
while (candidate) {
error += QLatin1String("\n ") +
- QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).methodSignature().constData());
- candidate = RelatedMethod(object, candidate, dummy);
+ QString::fromUtf8(object.metaObject()->method(candidate->coreIndex).methodSignature().constData());
+ candidate = RelatedMethod(object, candidate, dummy, propertyCache);
}
return QV8Engine::getV4(engine)->throwError(error);
@@ -1738,33 +1736,60 @@ QV4::ReturnedValue CallArgument::toValue(QV8Engine *engine)
ReturnedValue QObjectMethod::create(ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal)
{
- return (scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope, object, index, qmlGlobal))->asReturnedValue();
+ Scope valueScope(scope);
+ Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope));
+ method->d()->object = object;
+
+ if (QQmlData *ddata = QQmlData::get(object))
+ method->d()->propertyCache = ddata->propertyCache;
+
+ method->d()->index = index;
+ method->d()->qmlGlobal = qmlGlobal;
+ method->d()->valueTypeWrapper = Primitive::undefinedValue();
+ return method.asReturnedValue();
}
-Heap::QObjectMethod::QObjectMethod(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal)
+ReturnedValue QObjectMethod::create(ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const ValueRef qmlGlobal)
+{
+ Scope valueScope(scope);
+ Scoped<QObjectMethod> method(valueScope, scope->d()->engine->memoryManager->alloc<QObjectMethod>(scope));
+ method->d()->propertyCache = valueType->d()->propertyCache;
+ method->d()->index = index;
+ method->d()->qmlGlobal = qmlGlobal;
+ method->d()->valueTypeWrapper = valueType;
+ return method.asReturnedValue();
+}
+
+Heap::QObjectMethod::QObjectMethod(QV4::ExecutionContext *scope)
: Heap::FunctionObject(scope)
- , object(object)
- , index(index)
{
- this->qmlGlobal = qmlGlobal;
setVTable(QV4::QObjectMethod::staticVTable());
subtype = WrappedQtMethod;
}
+const QMetaObject *Heap::QObjectMethod::metaObject()
+{
+ if (propertyCache)
+ return propertyCache->createMetaObject();
+ return object->metaObject();
+}
+
QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx)
{
QString result;
- if (d()->object) {
- QString objectName = d()->object->objectName();
+ if (const QMetaObject *metaObject = d()->metaObject()) {
- result += QString::fromUtf8(d()->object->metaObject()->className());
+ result += QString::fromUtf8(metaObject->className());
result += QLatin1String("(0x");
result += QString::number((quintptr)d()->object.data(),16);
- if (!objectName.isEmpty()) {
- result += QLatin1String(", \"");
- result += objectName;
- result += QLatin1Char('\"');
+ if (d()->object) {
+ QString objectName = d()->object->objectName();
+ if (!objectName.isEmpty()) {
+ result += QLatin1String(", \"");
+ result += objectName;
+ result += QLatin1Char('\"');
+ }
}
result += QLatin1Char(')');
@@ -1809,25 +1834,26 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
else if (d()->index == ToStringMethod)
return method_toString(context);
- QObject *object = d()->object.data();
- if (!object)
- return Encode::undefined();
-
QV8Engine *v8Engine = context->d()->engine->v8Engine;
- QQmlPropertyData method;
+ QQmlObjectOrGadget object(d()->object.data());
+ if (!d()->object) {
+ Scoped<QQmlValueTypeWrapper> wrapper(scope, d()->valueTypeWrapper);
+ if (!wrapper)
+ return Encode::undefined();
- if (QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(object)->declarativeData)) {
- if (ddata->propertyCache) {
- QQmlPropertyData *data = ddata->propertyCache->method(d()->index);
- if (!data)
- return QV4::Encode::undefined();
- method = *data;
- }
+ object = QQmlObjectOrGadget(d()->propertyCache.data(), wrapper->d()->type->gadget());
}
- if (method.coreIndex == -1) {
- const QMetaObject *mo = object->metaObject();
+ QQmlPropertyData method;
+
+ if (d()->propertyCache) {
+ QQmlPropertyData *data = d()->propertyCache->method(d()->index);
+ if (!data)
+ return QV4::Encode::undefined();
+ method = *data;
+ } else {
+ const QMetaObject *mo = d()->object->metaObject();
const QMetaMethod moMethod = mo->method(d()->index);
method.load(moMethod);
@@ -1857,7 +1883,7 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
QQmlV4Function *funcptr = &func;
void *args[] = { 0, &funcptr };
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method.coreIndex, args);
+ object.metacall(QMetaObject::InvokeMetaMethod, method.coreIndex, args);
return rv.asReturnedValue();
}
@@ -1865,13 +1891,15 @@ ReturnedValue QObjectMethod::callInternal(CallData *callData)
if (!method.isOverload()) {
return CallPrecise(object, method, v8Engine, callData);
} else {
- return CallOverloaded(object, method, v8Engine, callData);
+ return CallOverloaded(object, method, v8Engine, callData, d()->propertyCache);
}
}
void QObjectMethod::markObjects(Heap::Base *that, ExecutionEngine *e)
{
- static_cast<QObjectMethod::Data*>(that)->qmlGlobal.mark(e);
+ QObjectMethod::Data *This = static_cast<QObjectMethod::Data*>(that);
+ This->qmlGlobal.mark(e);
+ This->valueTypeWrapper.mark(e);
}
DEFINE_OBJECT_VTABLE(QObjectMethod);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 5796241a8a..f0dd440ce3 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -75,10 +75,15 @@ struct QObjectWrapper : Object {
};
struct QObjectMethod : FunctionObject {
- QObjectMethod(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal);
+ QObjectMethod(QV4::ExecutionContext *scope);
QPointer<QObject> object;
+ QQmlRefPointer<QQmlPropertyCache> propertyCache;
int index;
Value qmlGlobal;
+
+ Value valueTypeWrapper;
+
+ const QMetaObject *metaObject();
};
struct QmlSignalHandler : Object {
@@ -133,6 +138,8 @@ private:
static ReturnedValue method_disconnect(CallContext *ctx);
};
+struct QQmlValueTypeWrapper;
+
struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
{
V4_OBJECT2(QObjectMethod, QV4::FunctionObject)
@@ -141,6 +148,7 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
enum { DestroyMethod = -1, ToStringMethod = -2 };
static ReturnedValue create(QV4::ExecutionContext *scope, QObject *object, int index, const ValueRef qmlGlobal = Primitive::undefinedValue());
+ static ReturnedValue create(QV4::ExecutionContext *scope, QQmlValueTypeWrapper *valueType, int index, const ValueRef qmlGlobal = Primitive::undefinedValue());
int methodIndex() const { return d()->index; }
QObject *object() const { return d()->object.data(); }
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 74a24f81fc..9191f26a28 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -1653,4 +1653,12 @@ int *QQmlMetaObject::methodParameterTypes(int index, QVarLengthArray<int, 9> &du
}
}
+void QQmlObjectOrGadget::metacall(QMetaObject::Call type, int index, void **argv) const
+{
+ if (ptr.isT1())
+ QMetaObject::metacall(ptr.asT1(), type, index, argv);
+ else
+ _m.asT1()->metaObject()->d.static_metacall(reinterpret_cast<QObject*>(ptr.asT2()), type, index, argv);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index 82217f3b22..b34a5ded90 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -430,10 +430,28 @@ public:
static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
-private:
+protected:
QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
};
+class QQmlObjectOrGadget: public QQmlMetaObject
+{
+public:
+ QQmlObjectOrGadget(QObject *obj)
+ : QQmlMetaObject(obj),
+ ptr(obj)
+ {}
+ QQmlObjectOrGadget(QQmlPropertyCache *propertyCache, void *gadget)
+ : QQmlMetaObject(propertyCache)
+ , ptr(gadget)
+ {}
+
+ void metacall(QMetaObject::Call type, int index, void **argv) const;
+
+private:
+ QBiPointer<QObject, void> ptr;
+};
+
QQmlPropertyData::QQmlPropertyData()
{
propType = 0;
diff --git a/src/qml/qml/qqmlvaluetype_p.h b/src/qml/qml/qqmlvaluetype_p.h
index 2f6a192f77..cd9e51957d 100644
--- a/src/qml/qml/qqmlvaluetype_p.h
+++ b/src/qml/qml/qqmlvaluetype_p.h
@@ -72,6 +72,8 @@ public:
QString toString() const;
bool isEqual(const QVariant &value) const;
+ void *gadget() const { return gadgetPtr; }
+
inline int userType() const
{
return typeId;
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 72a16a6e0a..8de5df9792 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -256,7 +256,7 @@ ReturnedValue QQmlValueTypeWrapper::get(Managed *m, String *name, bool *hasPrope
// calling a Q_INVOKABLE function of a value type
Scope scope(v4);
ScopedContext c(scope, v4->rootContext());
- return QV4::QObjectMethod::create(c, r->d()->type.data(), result->coreIndex);
+ return QV4::QObjectMethod::create(c, r, result->coreIndex);
}
#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \