Michael Goddard <michael.goddard@trolltech.com>
authorhausmann@webkit.org <hausmann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Jan 2008 13:51:26 +0000 (13:51 +0000)
committerhausmann@webkit.org <hausmann@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 Jan 2008 13:51:26 +0000 (13:51 +0000)
Add support for calling QObjects.
Add support for invokeDefaultMethod (via a call to
a specific slot), and also allow using it as a
constructor, like QtScript.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@29759 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JavaScriptCore/ChangeLog
JavaScriptCore/bindings/qt/qt_class.cpp
JavaScriptCore/bindings/qt/qt_instance.cpp
JavaScriptCore/bindings/qt/qt_instance.h
JavaScriptCore/bindings/qt/qt_runtime.cpp
JavaScriptCore/bindings/qt/qt_runtime.h

index f66e040..28fd3e9 100644 (file)
@@ -2,6 +2,31 @@
 
         Reviewed by Simon.
 
+        Add support for calling QObjects.
+        Add support for invokeDefaultMethod (via a call to
+        a specific slot), and also allow using it as a
+        constructor, like QtScript.
+        
+
+        * bindings/qt/qt_class.cpp:
+        (KJS::Bindings::QtClass::fallbackObject):
+        * bindings/qt/qt_instance.cpp:
+        (KJS::Bindings::QtRuntimeObjectImp::construct):
+        (KJS::Bindings::QtInstance::QtInstance):
+        (KJS::Bindings::QtInstance::~QtInstance):
+        (KJS::Bindings::QtInstance::implementsCall):
+        (KJS::Bindings::QtInstance::invokeDefaultMethod):
+        * bindings/qt/qt_instance.h:
+        * bindings/qt/qt_runtime.cpp:
+        (KJS::Bindings::findMethodIndex):
+        (KJS::Bindings::QtRuntimeMetaMethod::QtRuntimeMetaMethod):
+        (KJS::Bindings::QtRuntimeMetaMethod::callAsFunction):
+        * bindings/qt/qt_runtime.h:
+
+2008-01-24  Michael Goddard  <michael.goddard@trolltech.com>
+
+        Reviewed by Simon.
+
         Code style cleanups.
         Add spaces before/after braces in inline function.
         
index 26d381b..59730b8 100644 (file)
@@ -89,7 +89,7 @@ JSValue* QtClass::fallbackObject(ExecState *exec, Instance *inst, const Identifi
     if (normal.contains('(') && (index = m_metaObject->indexOfMethod(normal)) != -1) {
         QMetaMethod m = m_metaObject->method(index);
         if (m.access() != QMetaMethod::Private) {
-            JSValue *val = new QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal);
+            JSValue *val = new QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false);
             gcProtect(val);
             qtinst->m_methods.insert(name, val);
             return val;
@@ -107,7 +107,7 @@ JSValue* QtClass::fallbackObject(ExecState *exec, Instance *inst, const Identifi
         signature.truncate(signature.indexOf('('));
 
         if (normal == signature) {
-            JSValue* val = new QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal);
+            JSValue* val = new QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false);
             gcProtect(val);
             qtinst->m_methods.insert(name, val);
             return val;
index e555137..0197b84 100644 (file)
 #include "config.h"
 #include "qt_instance.h"
 
+#include "JSGlobalObject.h"
 #include "list.h"
 #include "qt_class.h"
 #include "qt_runtime.h"
 #include "PropertyNameArray.h"
 #include "runtime_object.h"
+#include "object_object.h"
 
 #include <qmetaobject.h>
 #include <qdebug.h>
@@ -48,6 +50,10 @@ class QtRuntimeObjectImp : public RuntimeObjectImp {
         QtRuntimeObjectImp(Instance*);
         ~QtRuntimeObjectImp();
         virtual void invalidate();
+
+        // Additions
+        virtual bool implementsConstruct() const {return implementsCall();}
+        virtual JSObject* construct(ExecState* exec, const List& args);
     protected:
         void removeFromCache();
 };
@@ -76,12 +82,25 @@ void QtRuntimeObjectImp::removeFromCache()
         cachedObjects.remove(key);
 }
 
+JSObject* QtRuntimeObjectImp::construct(ExecState* exec, const List& args)
+{
+    // ECMA 15.2.2.1 (?)
+    JSValue *val = callAsFunction(exec, this, args);
+
+    if (!val || val->type() == NullType || val->type() == UndefinedType)
+        return new JSObject(exec->lexicalGlobalObject()->objectPrototype());
+    else
+        return val->toObject(exec);
+}
+
 // QtInstance
 QtInstance::QtInstance(QObject* o, PassRefPtr<RootObject> rootObject)
     : Instance(rootObject)
     , m_class(0)
     , m_object(o)
     , m_hashkey(o)
+    , m_defaultMethod(0)
+    , m_defaultMethodIndex(-2)
 {
 }
 
@@ -102,6 +121,9 @@ QtInstance::~QtInstance()
         delete f;
     }
     m_fields.clear();
+
+    if (m_defaultMethod)
+        gcUnprotect(m_defaultMethod);
 }
 
 QtInstance* QtInstance::getQtInstance(QObject* o, PassRefPtr<RootObject> rootObject)
@@ -147,12 +169,6 @@ void QtInstance::end()
     // Do nothing.
 }
 
-bool QtInstance::implementsCall() const
-{
-    // typeof object that implements call == function
-    return false;
-}
-
 void QtInstance::getPropertyNames(ExecState* , PropertyNameArray& array)
 {
     // This is the enumerable properties, so put:
@@ -191,13 +207,51 @@ JSValue* QtInstance::invokeMethod(ExecState*, const MethodList&, const List&)
     return jsUndefined();
 }
 
-JSValue* QtInstance::invokeDefaultMethod(ExecState* exec, const List& )
+bool QtInstance::implementsCall() const
 {
-    // ### QtScript tries to invoke a meta method qscript_call
-    if (!getObject()) {
-        return throwError(exec, GeneralError, "cannot call function of deleted QObject");
+    // See if we have qscript_call
+    if (m_defaultMethodIndex == -2) {
+        if (m_object) {
+            const QMetaObject* meta = m_object->metaObject();
+            int count = meta->methodCount();
+            const QByteArray defsig("qscript_call");
+            for (int index = count - 1; index >= 0; --index) {
+                const QMetaMethod m = meta->method(index);
+
+                QByteArray signature = m.signature();
+                signature.truncate(signature.indexOf('('));
+
+                if (defsig == signature) {
+                    m_defaultMethodIndex = index;
+                    break;
+                }
+            }
+        }
+
+        if (m_defaultMethodIndex == -2) // Not checked
+            m_defaultMethodIndex = -1; // No qscript_call
     }
-    return jsUndefined();
+
+    // typeof object that implements call == function
+    return (m_defaultMethodIndex >= 0);
+}
+
+JSValue* QtInstance::invokeDefaultMethod(ExecState* exec, const List& args)
+{
+    // QtScript tries to invoke a meta method qscript_call
+    if (!getObject())
+        return throwError(exec, GeneralError, "cannot call function of deleted QObject");
+
+    // implementsCall will update our default method cache, if possible
+    if (implementsCall()) {
+        if (!m_defaultMethod) {
+            m_defaultMethod = new QtRuntimeMetaMethod(exec, Identifier("[[Call]]"),this, m_defaultMethodIndex, QByteArray("qscript_call"), true);
+            gcProtect(m_defaultMethod);
+        }
+
+        return m_defaultMethod->callAsFunction(exec, 0, args); // Luckily QtRuntimeMetaMethod ignores the obj parameter
+    } else
+        return throwError(exec, TypeError, "not a function");
 }
 
 JSValue* QtInstance::defaultValue(JSType hint) const
index e57ab23..2304ac5 100644 (file)
@@ -33,6 +33,7 @@ namespace Bindings {
 
 class QtClass;
 class QtField;
+class QtRuntimeMetaMethod;
 
 class QtInstance : public Instance
 {
@@ -73,6 +74,8 @@ private:
     QObject* m_hashkey;
     mutable QHash<QByteArray,JSValue*> m_methods;
     mutable QHash<QString,QtField*> m_fields;
+    mutable QtRuntimeMetaMethod* m_defaultMethod;
+    mutable int m_defaultMethodIndex;
 };
 
 } // namespace Bindings
index 71963a4..55744b4 100644 (file)
@@ -904,6 +904,7 @@ static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
 static int findMethodIndex(ExecState* exec,
                            const QMetaObject* meta,
                            const QByteArray& signature,
+                           bool allowPrivate,
                            const List& jsArgs,
                            QVarLengthArray<QVariant, 10> &vars,
                            void** vvars,
@@ -918,7 +919,7 @@ static int findMethodIndex(ExecState* exec,
         const QMetaMethod m = meta->method(i);
 
         // Don't choose private methods
-        if (m.access() == QMetaMethod::Private)
+        if (m.access() == QMetaMethod::Private && !allowPrivate)
             continue;
 
         // try and find all matching named methods
@@ -1148,7 +1149,7 @@ static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray
     return index;
 }
 
-QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature)
+QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate)
     : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, ident, inst)
 {
     QW_D(QtRuntimeMetaMethod);
@@ -1156,6 +1157,7 @@ QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& iden
     d->m_index = index;
     d->m_connect = 0;
     d->m_disconnect = 0;
+    d->m_allowPrivate = allowPrivate;
 }
 
 void QtRuntimeMetaMethod::mark()
@@ -1186,7 +1188,7 @@ JSValue* QtRuntimeMetaMethod::callAsFunction(ExecState* exec, JSObject*, const L
 
         int methodIndex;
         JSObject* errorObj = 0;
-        if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, args, vargs, (void**)qargs, &errorObj)) != -1) {
+        if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, args, vargs, (void **)qargs, &errorObj)) != -1) {
             if (obj->qt_metacall(QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
                 return jsUndefined();
 
index af239d5..e44af7b 100644 (file)
@@ -121,6 +121,7 @@ class QtRuntimeMetaMethodData : public QtRuntimeMethodData {
     public:
         ~QtRuntimeMetaMethodData();
         QByteArray m_signature;
+        bool m_allowPrivate;
         int m_index;
         QtRuntimeConnectionMethod *m_connect;
         QtRuntimeConnectionMethod *m_disconnect;
@@ -152,7 +153,7 @@ protected:
 class QtRuntimeMetaMethod : public QtRuntimeMethod
 {
 public:
-    QtRuntimeMetaMethod(ExecState *exec, const Identifier &n, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature );
+    QtRuntimeMetaMethod(ExecState *exec, const Identifier &n, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate);
 
     virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
     virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);