summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/bridge/qt
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/bridge/qt
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/bridge/qt')
-rw-r--r--Source/WebCore/bridge/qt/qt_class.cpp225
-rw-r--r--Source/WebCore/bridge/qt/qt_class.h59
-rw-r--r--Source/WebCore/bridge/qt/qt_instance.cpp397
-rw-r--r--Source/WebCore/bridge/qt/qt_instance.h96
-rw-r--r--Source/WebCore/bridge/qt/qt_pixmapruntime.cpp369
-rw-r--r--Source/WebCore/bridge/qt/qt_pixmapruntime.h54
-rw-r--r--Source/WebCore/bridge/qt/qt_runtime.cpp1914
-rw-r--r--Source/WebCore/bridge/qt/qt_runtime.h242
8 files changed, 3356 insertions, 0 deletions
diff --git a/Source/WebCore/bridge/qt/qt_class.cpp b/Source/WebCore/bridge/qt/qt_class.cpp
new file mode 100644
index 0000000..4c29c69
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_class.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "qt_class.h"
+
+#include "Identifier.h"
+#include "qt_instance.h"
+#include "qt_runtime.h"
+
+#include <qdebug.h>
+#include <qmetaobject.h>
+
+namespace JSC {
+namespace Bindings {
+
+QtClass::QtClass(const QMetaObject* mo)
+ : m_metaObject(mo)
+{
+}
+
+QtClass::~QtClass()
+{
+}
+
+typedef HashMap<const QMetaObject*, QtClass*> ClassesByMetaObject;
+static ClassesByMetaObject* classesByMetaObject = 0;
+
+QtClass* QtClass::classForObject(QObject* o)
+{
+ if (!classesByMetaObject)
+ classesByMetaObject = new ClassesByMetaObject;
+
+ const QMetaObject* mo = o->metaObject();
+ QtClass* aClass = classesByMetaObject->get(mo);
+ if (!aClass) {
+ aClass = new QtClass(mo);
+ classesByMetaObject->set(mo, aClass);
+ }
+
+ return aClass;
+}
+
+const char* QtClass::name() const
+{
+ return m_metaObject->className();
+}
+
+// We use this to get at signals (so we can return a proper function object,
+// and not get wrapped in RuntimeMethod). Also, use this for methods,
+// so we can cache the object and return the same object for the same
+// identifier.
+JSValue QtClass::fallbackObject(ExecState* exec, Instance* inst, const Identifier& identifier)
+{
+ QtInstance* qtinst = static_cast<QtInstance*>(inst);
+
+ const UString& ustring = identifier.ustring();
+ const QByteArray name = QString(reinterpret_cast<const QChar*>(ustring.characters()), ustring.length()).toAscii();
+
+ // First see if we have a cache hit
+ JSObject* val = qtinst->m_methods.value(name);
+ if (val)
+ return val;
+
+ // Nope, create an entry
+ const QByteArray normal = QMetaObject::normalizedSignature(name.constData());
+
+ // See if there is an exact match
+ int index = -1;
+ if (normal.contains('(') && (index = m_metaObject->indexOfMethod(normal)) != -1) {
+ QMetaMethod m = m_metaObject->method(index);
+ if (m.access() != QMetaMethod::Private) {
+ QtRuntimeMetaMethod* val = new (exec) QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false);
+ qtinst->m_methods.insert(name, val);
+ return val;
+ }
+ }
+
+ // Nope.. try a basename match
+ const int count = m_metaObject->methodCount();
+ for (index = count - 1; index >= 0; --index) {
+ const QMetaMethod m = m_metaObject->method(index);
+ if (m.access() == QMetaMethod::Private)
+ continue;
+
+ int iter = 0;
+ const char* signature = m.signature();
+ while (signature[iter] && signature[iter] != '(')
+ ++iter;
+
+ if (normal == QByteArray::fromRawData(signature, iter)) {
+ QtRuntimeMetaMethod* val = new (exec) QtRuntimeMetaMethod(exec, identifier, static_cast<QtInstance*>(inst), index, normal, false);
+ qtinst->m_methods.insert(name, val);
+ return val;
+ }
+ }
+
+ return jsUndefined();
+}
+
+// This functionality is handled by the fallback case above...
+MethodList QtClass::methodsNamed(const Identifier&, Instance*) const
+{
+ return MethodList();
+}
+
+// ### we may end up with a different search order than QtScript by not
+// folding this code into the fallbackMethod above, but Fields propagate out
+// of the binding code
+Field* QtClass::fieldNamed(const Identifier& identifier, Instance* instance) const
+{
+ // Check static properties first
+ QtInstance* qtinst = static_cast<QtInstance*>(instance);
+
+ QObject* obj = qtinst->getObject();
+ const UString& ustring = identifier.ustring();
+ const QString name(reinterpret_cast<const QChar*>(ustring.characters()), ustring.length());
+ const QByteArray ascii = name.toAscii();
+
+ // First check for a cached field
+ QtField* f = qtinst->m_fields.value(name);
+
+ if (obj) {
+ if (f) {
+ // We only cache real metaproperties, but we do store the
+ // other types so we can delete them later
+ if (f->fieldType() == QtField::MetaProperty)
+ return f;
+#ifndef QT_NO_PROPERTIES
+ if (f->fieldType() == QtField::DynamicProperty) {
+ if (obj->dynamicPropertyNames().indexOf(ascii) >= 0)
+ return f;
+ // Dynamic property that disappeared
+ qtinst->m_fields.remove(name);
+ delete f;
+ }
+#endif
+ else {
+ const QList<QObject*>& children = obj->children();
+ const int count = children.size();
+ for (int index = 0; index < count; ++index) {
+ QObject* child = children.at(index);
+ if (child->objectName() == name)
+ return f;
+ }
+
+ // Didn't find it, delete it from the cache
+ qtinst->m_fields.remove(name);
+ delete f;
+ }
+ }
+
+ int index = m_metaObject->indexOfProperty(ascii);
+ if (index >= 0) {
+ const QMetaProperty prop = m_metaObject->property(index);
+
+ if (prop.isScriptable(obj)) {
+ f = new QtField(prop);
+ qtinst->m_fields.insert(name, f);
+ return f;
+ }
+ }
+
+#ifndef QT_NO_PROPERTIES
+ // Dynamic properties
+ index = obj->dynamicPropertyNames().indexOf(ascii);
+ if (index >= 0) {
+ f = new QtField(ascii);
+ qtinst->m_fields.insert(name, f);
+ return f;
+ }
+#endif
+
+ // Child objects
+
+ const QList<QObject*>& children = obj->children();
+ const int count = children.count();
+ for (index = 0; index < count; ++index) {
+ QObject* child = children.at(index);
+ if (child->objectName() == name) {
+ f = new QtField(child);
+ qtinst->m_fields.insert(name, f);
+ return f;
+ }
+ }
+
+ // Nothing named this
+ return 0;
+ }
+ // For compatibility with qtscript, cached methods don't cause
+ // errors until they are accessed, so don't blindly create an error
+ // here.
+ if (qtinst->m_methods.contains(ascii))
+ return 0;
+
+#ifndef QT_NO_PROPERTIES
+ // deleted qobject, but can't throw an error from here (no exec)
+ // create a fake QtField that will throw upon access
+ if (!f) {
+ f = new QtField(ascii);
+ qtinst->m_fields.insert(name, f);
+ }
+#endif
+ return f;
+}
+
+}
+}
+
diff --git a/Source/WebCore/bridge/qt/qt_class.h b/Source/WebCore/bridge/qt/qt_class.h
new file mode 100644
index 0000000..9d55cc5
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_class.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef qt_class_h
+#define qt_class_h
+
+#include "Bridge.h"
+#include "qglobal.h"
+
+QT_BEGIN_NAMESPACE
+class QObject;
+struct QMetaObject;
+QT_END_NAMESPACE
+
+namespace JSC {
+namespace Bindings {
+
+
+class QtClass : public Class {
+protected:
+ QtClass(const QMetaObject*);
+
+public:
+ static QtClass* classForObject(QObject*);
+ virtual ~QtClass();
+
+ virtual const char* name() const;
+ virtual MethodList methodsNamed(const Identifier&, Instance*) const;
+ virtual Field* fieldNamed(const Identifier&, Instance*) const;
+
+ virtual JSValue fallbackObject(ExecState*, Instance*, const Identifier&);
+
+private:
+ QtClass(const QtClass&); // prohibit copying
+ QtClass& operator=(const QtClass&); // prohibit assignment
+
+ const QMetaObject* m_metaObject;
+};
+
+} // namespace Bindings
+} // namespace JSC
+
+#endif
diff --git a/Source/WebCore/bridge/qt/qt_instance.cpp b/Source/WebCore/bridge/qt/qt_instance.cpp
new file mode 100644
index 0000000..78263e9
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_instance.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "qt_instance.h"
+
+#include "Error.h"
+#include "JSDOMBinding.h"
+#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "ObjectPrototype.h"
+#include "PropertyNameArray.h"
+#include "qt_class.h"
+#include "qt_runtime.h"
+#include "runtime_object.h"
+
+#include <qdebug.h>
+#include <qhash.h>
+#include <qmetaobject.h>
+#include <qmetatype.h>
+
+namespace JSC {
+namespace Bindings {
+
+// Cache QtInstances
+typedef QMultiHash<void*, QtInstance*> QObjectInstanceMap;
+static QObjectInstanceMap cachedInstances;
+
+// Derived RuntimeObject
+class QtRuntimeObject : public RuntimeObject {
+public:
+ QtRuntimeObject(ExecState*, JSGlobalObject*, PassRefPtr<Instance>);
+
+ static const ClassInfo s_info;
+
+ virtual void markChildren(MarkStack& markStack)
+ {
+ RuntimeObject::markChildren(markStack);
+ QtInstance* instance = static_cast<QtInstance*>(getInternalInstance());
+ if (instance)
+ instance->markAggregate(markStack);
+ }
+
+ static PassRefPtr<Structure> createStructure(JSValue prototype)
+ {
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ }
+
+protected:
+ static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesMarkChildren;
+
+private:
+ virtual const ClassInfo* classInfo() const { return &s_info; }
+};
+
+const ClassInfo QtRuntimeObject::s_info = { "QtRuntimeObject", &RuntimeObject::s_info, 0, 0 };
+
+QtRuntimeObject::QtRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<Instance> instance)
+ : RuntimeObject(exec, globalObject, WebCore::deprecatedGetDOMStructure<QtRuntimeObject>(exec), instance)
+{
+}
+
+// QtInstance
+QtInstance::QtInstance(QObject* o, PassRefPtr<RootObject> rootObject, QScriptEngine::ValueOwnership ownership)
+ : Instance(rootObject)
+ , m_class(0)
+ , m_object(o)
+ , m_hashkey(o)
+ , m_defaultMethod(0)
+ , m_ownership(ownership)
+{
+}
+
+QtInstance::~QtInstance()
+{
+ JSLock lock(SilenceAssertionsOnly);
+
+ cachedInstances.remove(m_hashkey);
+
+ // clean up (unprotect from gc) the JSValues we've created
+ m_methods.clear();
+
+ qDeleteAll(m_fields);
+ m_fields.clear();
+
+ if (m_object) {
+ switch (m_ownership) {
+ case QScriptEngine::QtOwnership:
+ break;
+ case QScriptEngine::AutoOwnership:
+ if (m_object->parent())
+ break;
+ // fall through!
+ case QScriptEngine::ScriptOwnership:
+ delete m_object;
+ break;
+ }
+ }
+}
+
+PassRefPtr<QtInstance> QtInstance::getQtInstance(QObject* o, PassRefPtr<RootObject> rootObject, QScriptEngine::ValueOwnership ownership)
+{
+ JSLock lock(SilenceAssertionsOnly);
+
+ foreach (QtInstance* instance, cachedInstances.values(o))
+ if (instance->rootObject() == rootObject) {
+ // The garbage collector removes instances, but it may happen that the wrapped
+ // QObject dies before the gc kicks in. To handle that case we have to do an additional
+ // check if to see if the instance's wrapped object is still alive. If it isn't, then
+ // we have to create a new wrapper.
+ if (!instance->getObject())
+ cachedInstances.remove(instance->hashKey());
+ else
+ return instance;
+ }
+
+ RefPtr<QtInstance> ret = QtInstance::create(o, rootObject, ownership);
+ cachedInstances.insert(o, ret.get());
+
+ return ret.release();
+}
+
+bool QtInstance::getOwnPropertySlot(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return object->JSObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+void QtInstance::put(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ object->JSObject::put(exec, propertyName, value, slot);
+}
+
+void QtInstance::removeCachedMethod(JSObject* method)
+{
+ if (m_defaultMethod == method)
+ m_defaultMethod = 0;
+
+ for (QHash<QByteArray, JSObject*>::Iterator it = m_methods.begin(),
+ end = m_methods.end(); it != end; ++it)
+ if (it.value() == method) {
+ m_methods.erase(it);
+ return;
+ }
+}
+
+QtInstance* QtInstance::getInstance(JSObject* object)
+{
+ if (!object)
+ return 0;
+ if (!object->inherits(&QtRuntimeObject::s_info))
+ return 0;
+ return static_cast<QtInstance*>(static_cast<RuntimeObject*>(object)->getInternalInstance());
+}
+
+Class* QtInstance::getClass() const
+{
+ if (!m_class) {
+ if (!m_object)
+ return 0;
+ m_class = QtClass::classForObject(m_object);
+ }
+ return m_class;
+}
+
+RuntimeObject* QtInstance::newRuntimeObject(ExecState* exec)
+{
+ JSLock lock(SilenceAssertionsOnly);
+ m_methods.clear();
+ return new (exec) QtRuntimeObject(exec, exec->lexicalGlobalObject(), this);
+}
+
+void QtInstance::markAggregate(MarkStack& markStack)
+{
+ if (m_defaultMethod)
+ markStack.append(m_defaultMethod);
+ foreach (JSObject* val, m_methods.values()) {
+ if (val)
+ markStack.append(val);
+ }
+}
+
+void QtInstance::begin()
+{
+ // Do nothing.
+}
+
+void QtInstance::end()
+{
+ // Do nothing.
+}
+
+void QtInstance::getPropertyNames(ExecState* exec, PropertyNameArray& array)
+{
+ // This is the enumerable properties, so put:
+ // properties
+ // dynamic properties
+ // slots
+ QObject* obj = getObject();
+ if (obj) {
+ const QMetaObject* meta = obj->metaObject();
+
+ int i;
+ for (i = 0; i < meta->propertyCount(); i++) {
+ QMetaProperty prop = meta->property(i);
+ if (prop.isScriptable())
+ array.add(Identifier(exec, prop.name()));
+ }
+
+#ifndef QT_NO_PROPERTIES
+ QList<QByteArray> dynProps = obj->dynamicPropertyNames();
+ foreach (const QByteArray& ba, dynProps)
+ array.add(Identifier(exec, ba.constData()));
+#endif
+
+ const int methodCount = meta->methodCount();
+ for (i = 0; i < methodCount; i++) {
+ QMetaMethod method = meta->method(i);
+ if (method.access() != QMetaMethod::Private)
+ array.add(Identifier(exec, method.signature()));
+ }
+ }
+}
+
+JSValue QtInstance::getMethod(ExecState* exec, const Identifier& propertyName)
+{
+ if (!getClass())
+ return jsNull();
+ MethodList methodList = m_class->methodsNamed(propertyName, this);
+ return new (exec) RuntimeMethod(exec, exec->lexicalGlobalObject(), propertyName, methodList);
+}
+
+JSValue QtInstance::invokeMethod(ExecState*, RuntimeMethod*)
+{
+ // Implemented via fallbackMethod & QtRuntimeMetaMethod::callAsFunction
+ return jsUndefined();
+}
+
+JSValue QtInstance::defaultValue(ExecState* exec, PreferredPrimitiveType hint) const
+{
+ if (hint == PreferString)
+ return stringValue(exec);
+ if (hint == PreferNumber)
+ return numberValue(exec);
+ return valueOf(exec);
+}
+
+JSValue QtInstance::stringValue(ExecState* exec) const
+{
+ QObject* obj = getObject();
+ if (!obj)
+ return jsNull();
+
+ // Hmm.. see if there is a toString defined
+ QByteArray buf;
+ bool useDefault = true;
+ getClass();
+ if (m_class) {
+ // Cheat and don't use the full name resolution
+ int index = obj->metaObject()->indexOfMethod("toString()");
+ if (index >= 0) {
+ QMetaMethod m = obj->metaObject()->method(index);
+ // Check to see how much we can call it
+ if (m.access() != QMetaMethod::Private
+ && m.methodType() != QMetaMethod::Signal
+ && m.parameterTypes().isEmpty()) {
+ const char* retsig = m.typeName();
+ if (retsig && *retsig) {
+ QVariant ret(QMetaType::type(retsig), (void*)0);
+ void * qargs[1];
+ qargs[0] = ret.data();
+
+ if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, qargs) < 0) {
+ if (ret.isValid() && ret.canConvert(QVariant::String)) {
+ buf = ret.toString().toLatin1().constData(); // ### Latin 1? Ascii?
+ useDefault = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (useDefault) {
+ const QMetaObject* meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
+ QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed");
+ QString str = QString::fromUtf8("%0(name = \"%1\")")
+ .arg(QLatin1String(meta->className())).arg(name);
+
+ buf = str.toLatin1();
+ }
+ return jsString(exec, buf.constData());
+}
+
+JSValue QtInstance::numberValue(ExecState*) const
+{
+ return jsNumber(0);
+}
+
+JSValue QtInstance::booleanValue() const
+{
+ // ECMA 9.2
+ return jsBoolean(getObject());
+}
+
+JSValue QtInstance::valueOf(ExecState* exec) const
+{
+ return stringValue(exec);
+}
+
+// In qt_runtime.cpp
+JSValue convertQVariantToValue(ExecState*, PassRefPtr<RootObject> root, const QVariant& variant);
+QVariant convertValueToQVariant(ExecState*, JSValue, QMetaType::Type hint, int *distance);
+
+QByteArray QtField::name() const
+{
+ if (m_type == MetaProperty)
+ return m_property.name();
+ if (m_type == ChildObject && m_childObject)
+ return m_childObject->objectName().toLatin1();
+#ifndef QT_NO_PROPERTIES
+ if (m_type == DynamicProperty)
+ return m_dynamicProperty;
+#endif
+ return QByteArray(); // deleted child object
+}
+
+JSValue QtField::valueFromInstance(ExecState* exec, const Instance* inst) const
+{
+ const QtInstance* instance = static_cast<const QtInstance*>(inst);
+ QObject* obj = instance->getObject();
+
+ if (obj) {
+ QVariant val;
+ if (m_type == MetaProperty) {
+ if (m_property.isReadable())
+ val = m_property.read(obj);
+ else
+ return jsUndefined();
+ } else if (m_type == ChildObject)
+ val = QVariant::fromValue((QObject*) m_childObject);
+#ifndef QT_NO_PROPERTIES
+ else if (m_type == DynamicProperty)
+ val = obj->property(m_dynamicProperty);
+#endif
+ return convertQVariantToValue(exec, inst->rootObject(), val);
+ }
+ QString msg = QString(QLatin1String("cannot access member `%1' of deleted QObject")).arg(QLatin1String(name()));
+ return throwError(exec, createError(exec, msg.toLatin1().constData()));
+}
+
+void QtField::setValueToInstance(ExecState* exec, const Instance* inst, JSValue aValue) const
+{
+ if (m_type == ChildObject) // QtScript doesn't allow setting to a named child
+ return;
+
+ const QtInstance* instance = static_cast<const QtInstance*>(inst);
+ QObject* obj = instance->getObject();
+ if (obj) {
+ QMetaType::Type argtype = QMetaType::Void;
+ if (m_type == MetaProperty)
+ argtype = (QMetaType::Type) QMetaType::type(m_property.typeName());
+
+ // dynamic properties just get any QVariant
+ QVariant val = convertValueToQVariant(exec, aValue, argtype, 0);
+ if (m_type == MetaProperty) {
+ if (m_property.isWritable())
+ m_property.write(obj, val);
+ }
+#ifndef QT_NO_PROPERTIES
+ else if (m_type == DynamicProperty)
+ obj->setProperty(m_dynamicProperty.constData(), val);
+#endif
+ } else {
+ QString msg = QString(QLatin1String("cannot access member `%1' of deleted QObject")).arg(QLatin1String(name()));
+ throwError(exec, createError(exec, msg.toLatin1().constData()));
+ }
+}
+
+
+}
+}
diff --git a/Source/WebCore/bridge/qt/qt_instance.h b/Source/WebCore/bridge/qt/qt_instance.h
new file mode 100644
index 0000000..dd24a92
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_instance.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef qt_instance_h
+#define qt_instance_h
+
+#include "Bridge.h"
+#include "runtime_root.h"
+#include <QtScript/qscriptengine.h>
+#include <qhash.h>
+#include <qpointer.h>
+#include <qset.h>
+
+namespace JSC {
+
+namespace Bindings {
+
+class QtClass;
+class QtField;
+class QtRuntimeMetaMethod;
+
+class QtInstance : public Instance {
+public:
+ ~QtInstance();
+
+ virtual Class* getClass() const;
+ virtual RuntimeObject* newRuntimeObject(ExecState*);
+
+ virtual void begin();
+ virtual void end();
+
+ virtual JSValue valueOf(ExecState*) const;
+ virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
+
+ void markAggregate(MarkStack&);
+
+ virtual JSValue getMethod(ExecState* exec, const Identifier& propertyName);
+ virtual JSValue invokeMethod(ExecState*, RuntimeMethod*);
+
+ virtual void getPropertyNames(ExecState*, PropertyNameArray&);
+
+ JSValue stringValue(ExecState* exec) const;
+ JSValue numberValue(ExecState* exec) const;
+ JSValue booleanValue() const;
+
+ QObject* getObject() const { return m_object; }
+ QObject* hashKey() const { return m_hashkey; }
+
+ static PassRefPtr<QtInstance> getQtInstance(QObject*, PassRefPtr<RootObject>, QScriptEngine::ValueOwnership ownership);
+
+ virtual bool getOwnPropertySlot(JSObject*, ExecState*, const Identifier&, PropertySlot&);
+ virtual void put(JSObject*, ExecState*, const Identifier&, JSValue, PutPropertySlot&);
+
+ void removeCachedMethod(JSObject*);
+
+ static QtInstance* getInstance(JSObject*);
+
+private:
+ static PassRefPtr<QtInstance> create(QObject *instance, PassRefPtr<RootObject> rootObject, QScriptEngine::ValueOwnership ownership)
+ {
+ return adoptRef(new QtInstance(instance, rootObject, ownership));
+ }
+
+ friend class QtClass;
+ friend class QtField;
+ QtInstance(QObject*, PassRefPtr<RootObject>, QScriptEngine::ValueOwnership ownership); // Factory produced only..
+ mutable QtClass* m_class;
+ QPointer<QObject> m_object;
+ QObject* m_hashkey;
+ mutable QHash<QByteArray, JSObject*> m_methods;
+ mutable QHash<QString, QtField*> m_fields;
+ mutable QtRuntimeMetaMethod* m_defaultMethod;
+ QScriptEngine::ValueOwnership m_ownership;
+};
+
+} // namespace Bindings
+
+} // namespace JSC
+
+#endif
diff --git a/Source/WebCore/bridge/qt/qt_pixmapruntime.cpp b/Source/WebCore/bridge/qt/qt_pixmapruntime.cpp
new file mode 100644
index 0000000..1ef20c3
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_pixmapruntime.cpp
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include "config.h"
+#include "qt_pixmapruntime.h"
+
+#include "CachedImage.h"
+#include "HTMLImageElement.h"
+#include "JSGlobalObject.h"
+#include "JSHTMLImageElement.h"
+#include "JSLock.h"
+#include "ObjectPrototype.h"
+#include "StillImageQt.h"
+#include <QBuffer>
+#include <QByteArray>
+#include <QImage>
+#include <QPixmap>
+#include <QVariant>
+#include <runtime_method.h>
+#include <runtime_object.h>
+#include <runtime_root.h>
+
+using namespace WebCore;
+namespace JSC {
+
+namespace Bindings {
+
+class QtPixmapClass : public Class {
+public:
+ QtPixmapClass();
+ virtual MethodList methodsNamed(const Identifier&, Instance*) const;
+ virtual Field* fieldNamed(const Identifier&, Instance*) const;
+};
+
+
+class QtPixmapWidthField : public Field {
+public:
+ static const char* name() { return "width"; }
+ virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
+ {
+ return jsNumber(static_cast<const QtPixmapInstance*>(instance)->width());
+ }
+ virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
+};
+
+class QtPixmapHeightField : public Field {
+public:
+ static const char* name() { return "height"; }
+ virtual JSValue valueFromInstance(ExecState*, const Instance* instance) const
+ {
+ return jsNumber(static_cast<const QtPixmapInstance*>(instance)->height());
+ }
+ virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const {}
+};
+
+class QtPixmapRuntimeMethod : public Method {
+public:
+ virtual int numParameters() const
+ {
+ return 0;
+ }
+ virtual JSValue invoke(ExecState* exec, QtPixmapInstance*) = 0;
+
+};
+
+// this function receives an HTML image element as a parameter, makes it display the pixmap/image from Qt
+class QtPixmapAssignToElementMethod : public QtPixmapRuntimeMethod {
+public:
+ static const char* name() { return "assignToHTMLImageElement"; }
+ JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
+ {
+ if (!exec->argumentCount())
+ return jsUndefined();
+
+ JSObject* objectArg = exec->argument(0).toObject(exec);
+ if (!objectArg)
+ return jsUndefined();
+
+ if (!objectArg->inherits(&JSHTMLImageElement::s_info))
+ return jsUndefined();
+
+ // we now know that we have a valid <img> element as the argument, we can attach the pixmap to it.
+ PassRefPtr<StillImage> stillImage = WebCore::StillImage::create(instance->toPixmap());
+ HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(static_cast<JSHTMLImageElement*>(objectArg)->impl());
+ imageElement->setCachedImage(new CachedImage(stillImage.get()));
+ JSDOMGlobalObject* global = static_cast<JSDOMGlobalObject*>(instance->rootObject()->globalObject());
+ toJS(exec, global, imageElement->document());
+ return jsUndefined();
+ }
+
+ virtual int numParameters() const
+ {
+ return 1;
+ }
+};
+
+// this function encodes the image to a dataUrl, to be used in background etc. Note: very slow.
+class QtPixmapToDataUrlMethod : public QtPixmapRuntimeMethod {
+public:
+ static const char* name() { return "toDataUrl"; }
+ JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
+ {
+ QByteArray byteArray;
+ QBuffer buffer(&byteArray);
+ instance->toImage().save(&buffer, "PNG");
+ const QString encodedString = QString("data:image/png;base64,") + byteArray.toBase64();
+ const UString ustring((UChar*)encodedString.utf16(), encodedString.length());
+ return jsString(exec, ustring);
+ }
+};
+
+class QtPixmapToStringMethod : public QtPixmapRuntimeMethod {
+ public:
+ static const char* name() { return "toString"; }
+ JSValue invoke(ExecState* exec, QtPixmapInstance* instance)
+ {
+ return instance->valueOf(exec);
+ }
+};
+
+struct QtPixmapMetaData {
+ QtPixmapToDataUrlMethod toDataUrlMethod;
+ QtPixmapAssignToElementMethod assignToElementMethod;
+ QtPixmapToStringMethod toStringMethod;
+ QtPixmapHeightField heightField;
+ QtPixmapWidthField widthField;
+ QtPixmapClass cls;
+} qt_pixmap_metaData;
+
+// Derived RuntimeObject
+class QtPixmapRuntimeObject : public RuntimeObject {
+public:
+ QtPixmapRuntimeObject(ExecState*, JSGlobalObject*, PassRefPtr<Instance>);
+
+ static const ClassInfo s_info;
+
+ static PassRefPtr<Structure> createStructure(JSValue prototype)
+ {
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ }
+
+protected:
+ static const unsigned StructureFlags = RuntimeObject::StructureFlags | OverridesMarkChildren;
+
+private:
+ virtual const ClassInfo* classInfo() const { return &s_info; }
+};
+
+QtPixmapRuntimeObject::QtPixmapRuntimeObject(ExecState* exec, JSGlobalObject* globalObject, PassRefPtr<Instance> instance)
+ : RuntimeObject(exec, globalObject, WebCore::deprecatedGetDOMStructure<QtPixmapRuntimeObject>(exec), instance)
+{
+}
+
+const ClassInfo QtPixmapRuntimeObject::s_info = { "QtPixmapRuntimeObject", &RuntimeObject::s_info, 0, 0 };
+
+QtPixmapClass::QtPixmapClass()
+{
+}
+
+
+Class* QtPixmapInstance::getClass() const
+{
+ return &qt_pixmap_metaData.cls;
+}
+
+JSValue QtPixmapInstance::getMethod(ExecState* exec, const Identifier& propertyName)
+{
+ MethodList methodList = getClass()->methodsNamed(propertyName, this);
+ return new (exec) RuntimeMethod(exec, exec->lexicalGlobalObject(), propertyName, methodList);
+}
+
+JSValue QtPixmapInstance::invokeMethod(ExecState* exec, RuntimeMethod* runtimeMethod)
+{
+ const MethodList& methods = *runtimeMethod->methods();
+
+ if (methods.size() == 1) {
+ QtPixmapRuntimeMethod* method = static_cast<QtPixmapRuntimeMethod*>(methods[0]);
+ return method->invoke(exec, this);
+ }
+ return jsUndefined();
+}
+
+MethodList QtPixmapClass::methodsNamed(const Identifier& identifier, Instance*) const
+{
+ MethodList methods;
+ if (identifier == QtPixmapToDataUrlMethod::name())
+ methods.append(&qt_pixmap_metaData.toDataUrlMethod);
+ else if (identifier == QtPixmapAssignToElementMethod::name())
+ methods.append(&qt_pixmap_metaData.assignToElementMethod);
+ else if (identifier == QtPixmapToStringMethod::name())
+ methods.append(&qt_pixmap_metaData.toStringMethod);
+ return methods;
+}
+
+Field* QtPixmapClass::fieldNamed(const Identifier& identifier, Instance*) const
+{
+ if (identifier == QtPixmapWidthField::name())
+ return &qt_pixmap_metaData.widthField;
+ if (identifier == QtPixmapHeightField::name())
+ return &qt_pixmap_metaData.heightField;
+ return 0;
+}
+
+void QtPixmapInstance::getPropertyNames(ExecState*exec, PropertyNameArray& arr)
+{
+ arr.add(Identifier(exec, UString(QtPixmapToDataUrlMethod::name())));
+ arr.add(Identifier(exec, UString(QtPixmapAssignToElementMethod::name())));
+ arr.add(Identifier(exec, UString(QtPixmapToStringMethod::name())));
+ arr.add(Identifier(exec, UString(QtPixmapWidthField::name())));
+ arr.add(Identifier(exec, UString(QtPixmapHeightField::name())));
+}
+
+JSValue QtPixmapInstance::defaultValue(ExecState* exec, PreferredPrimitiveType ptype) const
+{
+ if (ptype == PreferNumber) {
+ return jsBoolean(
+ (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()) && !(data.value<QImage>()).isNull())
+ || (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()) && !data.value<QPixmap>().isNull()));
+ }
+
+ if (ptype == PreferString)
+ return valueOf(exec);
+
+ return jsUndefined();
+}
+
+JSValue QtPixmapInstance::valueOf(ExecState* exec) const
+{
+ const QString stringValue = QString("[Qt Native Pixmap %1,%2]").arg(width()).arg(height());
+ UString ustring((UChar*)stringValue.utf16(), stringValue.length());
+ return jsString(exec, ustring);
+}
+
+QtPixmapInstance::QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& d)
+ :Instance(rootObj), data(d)
+{
+}
+
+int QtPixmapInstance::width() const
+{
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
+ return data.value<QPixmap>().width();
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
+ return data.value<QImage>().width();
+ return 0;
+}
+
+int QtPixmapInstance::height() const
+{
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
+ return data.value<QPixmap>().height();
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
+ return data.value<QImage>().height();
+ return 0;
+}
+
+QPixmap QtPixmapInstance::toPixmap()
+{
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>()))
+ return data.value<QPixmap>();
+
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>())) {
+ const QPixmap pixmap = QPixmap::fromImage(data.value<QImage>());
+ data = QVariant::fromValue<QPixmap>(pixmap);
+ return pixmap;
+ }
+
+ return QPixmap();
+}
+
+QImage QtPixmapInstance::toImage()
+{
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QImage>()))
+ return data.value<QImage>();
+
+ if (data.type() == static_cast<QVariant::Type>(qMetaTypeId<QPixmap>())) {
+ const QImage image = data.value<QPixmap>().toImage();
+ data = QVariant::fromValue<QImage>(image);
+ return image;
+ }
+
+ return QImage();
+}
+
+QVariant QtPixmapInstance::variantFromObject(JSObject* object, QMetaType::Type hint)
+{
+ if (!object)
+ goto returnEmptyVariant;
+
+ if (object->inherits(&JSHTMLImageElement::s_info)) {
+ JSHTMLImageElement* elementJSWrapper = static_cast<JSHTMLImageElement*>(object);
+ HTMLImageElement* imageElement = static_cast<HTMLImageElement*>(elementJSWrapper->impl());
+
+ if (!imageElement)
+ goto returnEmptyVariant;
+
+ CachedImage* cachedImage = imageElement->cachedImage();
+ if (!cachedImage)
+ goto returnEmptyVariant;
+
+ Image* image = cachedImage->image();
+ if (!image)
+ goto returnEmptyVariant;
+
+ QPixmap* pixmap = image->nativeImageForCurrentFrame();
+ if (!pixmap)
+ goto returnEmptyVariant;
+
+ return (hint == static_cast<QMetaType::Type>(qMetaTypeId<QPixmap>()))
+ ? QVariant::fromValue<QPixmap>(*pixmap)
+ : QVariant::fromValue<QImage>(pixmap->toImage());
+ }
+
+ if (object->inherits(&QtPixmapRuntimeObject::s_info)) {
+ QtPixmapRuntimeObject* runtimeObject = static_cast<QtPixmapRuntimeObject*>(object);
+ QtPixmapInstance* instance = static_cast<QtPixmapInstance*>(runtimeObject->getInternalInstance());
+ if (!instance)
+ goto returnEmptyVariant;
+
+ if (hint == qMetaTypeId<QPixmap>())
+ return QVariant::fromValue<QPixmap>(instance->toPixmap());
+
+ if (hint == qMetaTypeId<QImage>())
+ return QVariant::fromValue<QImage>(instance->toImage());
+ }
+
+returnEmptyVariant:
+ if (hint == qMetaTypeId<QPixmap>())
+ return QVariant::fromValue<QPixmap>(QPixmap());
+ if (hint == qMetaTypeId<QImage>())
+ return QVariant::fromValue<QImage>(QImage());
+ return QVariant();
+}
+
+RuntimeObject* QtPixmapInstance::newRuntimeObject(ExecState* exec)
+{
+ return new(exec) QtPixmapRuntimeObject(exec, exec->lexicalGlobalObject(), this);
+}
+
+JSObject* QtPixmapInstance::createPixmapRuntimeObject(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& data)
+{
+ JSLock lock(SilenceAssertionsOnly);
+ RefPtr<QtPixmapInstance> instance = adoptRef(new QtPixmapInstance(root, data));
+ return instance->createRuntimeObject(exec);
+}
+
+bool QtPixmapInstance::canHandle(QMetaType::Type hint)
+{
+ return hint == qMetaTypeId<QImage>() || hint == qMetaTypeId<QPixmap>();
+}
+
+}
+
+}
diff --git a/Source/WebCore/bridge/qt/qt_pixmapruntime.h b/Source/WebCore/bridge/qt/qt_pixmapruntime.h
new file mode 100644
index 0000000..e2ae5e9
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_pixmapruntime.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef qt_pixmapruntime_h
+#define qt_pixmapruntime_h
+
+#include "Bridge.h"
+#include <QVariant>
+
+namespace JSC {
+
+namespace Bindings {
+
+class QtPixmapInstance : public Instance {
+ QVariant data;
+public:
+ QtPixmapInstance(PassRefPtr<RootObject> rootObj, const QVariant& newData);
+ virtual Class* getClass() const;
+ virtual JSValue getMethod(ExecState* exec, const Identifier& propertyName);
+ virtual JSValue invokeMethod(ExecState*, RuntimeMethod*);
+ virtual void getPropertyNames(ExecState*, PropertyNameArray&);
+
+ virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
+ virtual JSValue valueOf(ExecState* exec) const;
+ int width() const;
+ int height() const;
+ QPixmap toPixmap();
+ QImage toImage();
+ RuntimeObject* newRuntimeObject(ExecState* exec);
+ static JSObject* createPixmapRuntimeObject(ExecState*, PassRefPtr<RootObject>, const QVariant&);
+ static QVariant variantFromObject(JSObject*, QMetaType::Type hint);
+ static bool canHandle(QMetaType::Type hint);
+};
+
+}
+
+}
+#endif
diff --git a/Source/WebCore/bridge/qt/qt_runtime.cpp b/Source/WebCore/bridge/qt/qt_runtime.cpp
new file mode 100644
index 0000000..0fb811b
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_runtime.cpp
@@ -0,0 +1,1914 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "qt_runtime.h"
+
+#include "BooleanObject.h"
+#include "DateInstance.h"
+#include "DateMath.h"
+#include "DatePrototype.h"
+#include "DumpRenderTreeSupportQt.h"
+#include "FunctionPrototype.h"
+#include "Interpreter.h"
+#include "JSArray.h"
+#include "JSByteArray.h"
+#include "JSDocument.h"
+#include "JSDOMBinding.h"
+#include "JSDOMWindow.h"
+#include <JSFunction.h>
+#include "JSGlobalObject.h"
+#include "JSHTMLElement.h"
+#include "JSLock.h"
+#include "JSObject.h"
+#include "ObjectPrototype.h"
+#include "PropertyNameArray.h"
+#include "RegExpConstructor.h"
+#include "RegExpObject.h"
+#include "qdatetime.h"
+#include "qdebug.h"
+#include "qmetaobject.h"
+#include "qmetatype.h"
+#include "qobject.h"
+#include "qstringlist.h"
+#include "qt_instance.h"
+#include "qt_pixmapruntime.h"
+#include "qvarlengtharray.h"
+#include "qwebelement.h"
+#include <limits.h>
+#include <runtime/Error.h>
+#include <runtime_array.h>
+#include <runtime_object.h>
+
+// QtScript has these
+Q_DECLARE_METATYPE(QObjectList);
+Q_DECLARE_METATYPE(QList<int>);
+Q_DECLARE_METATYPE(QVariant);
+
+using namespace WebCore;
+
+namespace JSC {
+namespace Bindings {
+
+// Debugging
+//#define QTWK_RUNTIME_CONVERSION_DEBUG
+//#define QTWK_RUNTIME_MATCH_DEBUG
+
+class QWKNoDebug
+{
+public:
+ inline QWKNoDebug(){}
+ inline ~QWKNoDebug(){}
+
+ template<typename T>
+ inline QWKNoDebug &operator<<(const T &) { return *this; }
+};
+
+#ifdef QTWK_RUNTIME_CONVERSION_DEBUG
+#define qConvDebug() qDebug()
+#else
+#define qConvDebug() QWKNoDebug()
+#endif
+
+#ifdef QTWK_RUNTIME_MATCH_DEBUG
+#define qMatchDebug() qDebug()
+#else
+#define qMatchDebug() QWKNoDebug()
+#endif
+
+typedef enum {
+ Variant = 0,
+ Number,
+ Boolean,
+ String,
+ Date,
+ RegExp,
+ Array,
+ QObj,
+ Object,
+ Null,
+ RTArray,
+ JSByteArray
+} JSRealType;
+
+#if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
+QDebug operator<<(QDebug dbg, const JSRealType &c)
+{
+ const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
+ "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};
+
+ dbg.nospace() << "JSType(" << ((int)c) << ", " << map[c] << ")";
+
+ return dbg.space();
+}
+#endif
+
+// this is here as a proxy, so we'd have a class to friend in QWebElement,
+// as getting/setting a WebCore in QWebElement is private
+class QtWebElementRuntime {
+public:
+ static QWebElement create(Element* element)
+ {
+ return QWebElement(element);
+ }
+
+ static Element* get(const QWebElement& element)
+ {
+ return element.m_element;
+ }
+};
+
+// this is here as a proxy, so we'd have a class to friend in QDRTNode,
+// as getting/setting a WebCore in QDRTNode is private.
+// We only need to pass WebCore Nodes for layout tests.
+class QtDRTNodeRuntime {
+public:
+ static QDRTNode create(Node* node)
+ {
+ return QDRTNode(node);
+ }
+
+ static Node* get(const QDRTNode& node)
+ {
+ return node.m_node;
+ }
+};
+
+static JSRealType valueRealType(ExecState* exec, JSValue val)
+{
+ if (val.isNumber())
+ return Number;
+ else if (val.isString())
+ return String;
+ else if (val.isBoolean())
+ return Boolean;
+ else if (val.isNull())
+ return Null;
+ else if (isJSByteArray(&exec->globalData(), val))
+ return JSByteArray;
+ else if (val.isObject()) {
+ JSObject *object = val.toObject(exec);
+ if (object->inherits(&RuntimeArray::s_info)) // RuntimeArray 'inherits' from Array, but not in C++
+ return RTArray;
+ else if (object->inherits(&JSArray::info))
+ return Array;
+ else if (object->inherits(&DateInstance::info))
+ return Date;
+ else if (object->inherits(&RegExpObject::info))
+ return RegExp;
+ else if (object->inherits(&RuntimeObject::s_info))
+ return QObj;
+ return Object;
+ }
+
+ return String; // I don't know.
+}
+
+QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects, int recursionLimit)
+{
+ --recursionLimit;
+
+ if (!value || !recursionLimit)
+ return QVariant();
+
+ JSObject* object = 0;
+ if (value.isObject()) {
+ object = value.toObject(exec);
+ if (visitedObjects->contains(object))
+ return QVariant();
+
+ visitedObjects->add(object);
+ }
+
+ // check magic pointer values before dereferencing value
+ if (value == jsNaN()
+ || (value == jsUndefined()
+ && hint != QMetaType::QString
+ && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
+ if (distance)
+ *distance = -1;
+ return QVariant();
+ }
+
+ JSLock lock(SilenceAssertionsOnly);
+ JSRealType type = valueRealType(exec, value);
+ if (hint == QMetaType::Void) {
+ switch(type) {
+ case Number:
+ hint = QMetaType::Double;
+ break;
+ case Boolean:
+ hint = QMetaType::Bool;
+ break;
+ case String:
+ default:
+ hint = QMetaType::QString;
+ break;
+ case Date:
+ hint = QMetaType::QDateTime;
+ break;
+ case RegExp:
+ hint = QMetaType::QRegExp;
+ break;
+ case Object:
+ if (object->inherits(&NumberObject::info))
+ hint = QMetaType::Double;
+ else if (object->inherits(&BooleanObject::info))
+ hint = QMetaType::Bool;
+ else
+ hint = QMetaType::QVariantMap;
+ break;
+ case QObj:
+ hint = QMetaType::QObjectStar;
+ break;
+ case JSByteArray:
+ hint = QMetaType::QByteArray;
+ break;
+ case Array:
+ case RTArray:
+ hint = QMetaType::QVariantList;
+ break;
+ }
+ }
+
+ qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
+
+ if (value == jsNull()
+ && hint != QMetaType::QObjectStar
+ && hint != QMetaType::VoidStar
+ && hint != QMetaType::QString
+ && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
+ if (distance)
+ *distance = -1;
+ return QVariant();
+ }
+
+ QVariant ret;
+ int dist = -1;
+ switch (hint) {
+ case QMetaType::Bool:
+ if (type == Object && object->inherits(&BooleanObject::info))
+ ret = QVariant(asBooleanObject(value)->internalValue().toBoolean(exec));
+ else
+ ret = QVariant(value.toBoolean(exec));
+ if (type == Boolean)
+ dist = 0;
+ else
+ dist = 10;
+ break;
+
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ case QMetaType::Float:
+ case QMetaType::Double:
+ ret = QVariant(value.toNumber(exec));
+ ret.convert((QVariant::Type)hint);
+ if (type == Number) {
+ switch (hint) {
+ case QMetaType::Double:
+ dist = 0;
+ break;
+ case QMetaType::Float:
+ dist = 1;
+ break;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ dist = 2;
+ break;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ dist = 3;
+ break;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ dist = 4;
+ break;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ dist = 5;
+ break;
+ break;
+ default:
+ dist = 10;
+ break;
+ }
+ } else {
+ dist = 10;
+ }
+ break;
+
+ case QMetaType::QChar:
+ if (type == Number || type == Boolean) {
+ ret = QVariant(QChar((ushort)value.toNumber(exec)));
+ if (type == Boolean)
+ dist = 3;
+ else
+ dist = 6;
+ } else {
+ UString str = value.toString(exec);
+ ret = QVariant(QChar(str.length() ? *(const ushort*)str.impl()->characters() : 0));
+ if (type == String)
+ dist = 3;
+ else
+ dist = 10;
+ }
+ break;
+
+ case QMetaType::QString: {
+ if (value.isUndefinedOrNull()) {
+ if (distance)
+ *distance = 1;
+ return QString();
+ } else {
+ UString ustring = value.toString(exec);
+ ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()));
+ if (type == String)
+ dist = 0;
+ else
+ dist = 10;
+ }
+ break;
+ }
+
+ case QMetaType::QVariantMap:
+ if (type == Object || type == Array || type == RTArray) {
+ // Enumerate the contents of the object
+ PropertyNameArray properties(exec);
+ object->getPropertyNames(exec, properties);
+ PropertyNameArray::const_iterator it = properties.begin();
+
+ QVariantMap result;
+ int objdist = 0;
+ while(it != properties.end()) {
+ if (object->propertyIsEnumerable(exec, *it)) {
+ JSValue val = object->get(exec, *it);
+ QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
+ if (objdist >= 0) {
+ UString ustring = (*it).ustring();
+ QString id = QString((const QChar*)ustring.impl()->characters(), ustring.length());
+ result.insert(id, v);
+ }
+ }
+ ++it;
+ }
+ dist = 1;
+ ret = QVariant(result);
+ }
+ break;
+
+ case QMetaType::QVariantList:
+ if (type == RTArray) {
+ RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
+
+ QVariantList result;
+ int len = rtarray->getLength();
+ int objdist = 0;
+ qConvDebug() << "converting a " << len << " length Array";
+ for (int i = 0; i < len; ++i) {
+ JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
+ result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
+ if (objdist == -1) {
+ qConvDebug() << "Failed converting element at index " << i;
+ break; // Failed converting a list entry, so fail the array
+ }
+ }
+ if (objdist != -1) {
+ dist = 5;
+ ret = QVariant(result);
+ }
+ } else if (type == Array) {
+ JSArray* array = static_cast<JSArray*>(object);
+
+ QVariantList result;
+ int len = array->length();
+ int objdist = 0;
+ qConvDebug() << "converting a " << len << " length Array";
+ for (int i = 0; i < len; ++i) {
+ JSValue val = array->get(exec, i);
+ result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
+ if (objdist == -1) {
+ qConvDebug() << "Failed converting element at index " << i;
+ break; // Failed converting a list entry, so fail the array
+ }
+ }
+ if (objdist != -1) {
+ dist = 5;
+ ret = QVariant(result);
+ }
+ } else {
+ // Make a single length array
+ int objdist;
+ qConvDebug() << "making a single length variantlist";
+ QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
+ if (objdist != -1) {
+ QVariantList result;
+ result << var;
+ ret = QVariant(result);
+ dist = 10;
+ } else {
+ qConvDebug() << "failed making single length varlist";
+ }
+ }
+ break;
+
+ case QMetaType::QStringList: {
+ if (type == RTArray) {
+ RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
+
+ QStringList result;
+ int len = rtarray->getLength();
+ for (int i = 0; i < len; ++i) {
+ JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
+ UString ustring = val.toString(exec);
+ QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
+
+ result.append(qstring);
+ }
+ dist = 5;
+ ret = QVariant(result);
+ } else if (type == Array) {
+ JSArray* array = static_cast<JSArray*>(object);
+
+ QStringList result;
+ int len = array->length();
+ for (int i = 0; i < len; ++i) {
+ JSValue val = array->get(exec, i);
+ UString ustring = val.toString(exec);
+ QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
+
+ result.append(qstring);
+ }
+ dist = 5;
+ ret = QVariant(result);
+ } else {
+ // Make a single length array
+ UString ustring = value.toString(exec);
+ QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
+ QStringList result;
+ result.append(qstring);
+ ret = QVariant(result);
+ dist = 10;
+ }
+ break;
+ }
+
+ case QMetaType::QByteArray: {
+ if (type == JSByteArray) {
+ WTF::ByteArray* arr = asByteArray(value)->storage();
+ ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
+ dist = 0;
+ } else {
+ UString ustring = value.toString(exec);
+ ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()).toLatin1());
+ if (type == String)
+ dist = 5;
+ else
+ dist = 10;
+ }
+ break;
+ }
+
+ case QMetaType::QDateTime:
+ case QMetaType::QDate:
+ case QMetaType::QTime:
+ if (type == Date) {
+ DateInstance* date = static_cast<DateInstance*>(object);
+ GregorianDateTime gdt;
+ msToGregorianDateTime(exec, date->internalNumber(), true, gdt);
+ if (hint == QMetaType::QDateTime) {
+ ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
+ dist = 0;
+ } else if (hint == QMetaType::QDate) {
+ ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
+ dist = 1;
+ } else {
+ ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
+ dist = 2;
+ }
+ } else if (type == Number) {
+ double b = value.toNumber(exec);
+ GregorianDateTime gdt;
+ msToGregorianDateTime(exec, b, true, gdt);
+ if (hint == QMetaType::QDateTime) {
+ ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
+ dist = 6;
+ } else if (hint == QMetaType::QDate) {
+ ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
+ dist = 8;
+ } else {
+ ret = QTime(gdt.hour, gdt.minute, gdt.second);
+ dist = 10;
+ }
+#ifndef QT_NO_DATESTRING
+ } else if (type == String) {
+ UString ustring = value.toString(exec);
+ QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
+
+ if (hint == QMetaType::QDateTime) {
+ QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
+ if (!dt.isValid())
+ dt = QDateTime::fromString(qstring, Qt::TextDate);
+ if (!dt.isValid())
+ dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
+ if (!dt.isValid())
+ dt = QDateTime::fromString(qstring, Qt::LocaleDate);
+ if (dt.isValid()) {
+ ret = dt;
+ dist = 2;
+ }
+ } else if (hint == QMetaType::QDate) {
+ QDate dt = QDate::fromString(qstring, Qt::ISODate);
+ if (!dt.isValid())
+ dt = QDate::fromString(qstring, Qt::TextDate);
+ if (!dt.isValid())
+ dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
+ if (!dt.isValid())
+ dt = QDate::fromString(qstring, Qt::LocaleDate);
+ if (dt.isValid()) {
+ ret = dt;
+ dist = 3;
+ }
+ } else {
+ QTime dt = QTime::fromString(qstring, Qt::ISODate);
+ if (!dt.isValid())
+ dt = QTime::fromString(qstring, Qt::TextDate);
+ if (!dt.isValid())
+ dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
+ if (!dt.isValid())
+ dt = QTime::fromString(qstring, Qt::LocaleDate);
+ if (dt.isValid()) {
+ ret = dt;
+ dist = 3;
+ }
+ }
+#endif // QT_NO_DATESTRING
+ }
+ break;
+
+ case QMetaType::QRegExp:
+ if (type == RegExp) {
+/*
+ RegExpObject *re = static_cast<RegExpObject*>(object);
+*/
+ // Attempt to convert.. a bit risky
+ UString ustring = value.toString(exec);
+ QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
+
+ // this is of the form '/xxxxxx/i'
+ int firstSlash = qstring.indexOf(QLatin1Char('/'));
+ int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
+ if (firstSlash >=0 && lastSlash > firstSlash) {
+ QRegExp realRe;
+
+ realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
+
+ if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
+ realRe.setCaseSensitivity(Qt::CaseInsensitive);
+
+ ret = qVariantFromValue(realRe);
+ dist = 0;
+ } else {
+ qConvDebug() << "couldn't parse a JS regexp";
+ }
+ } else if (type == String) {
+ UString ustring = value.toString(exec);
+ QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
+
+ QRegExp re(qstring);
+ if (re.isValid()) {
+ ret = qVariantFromValue(re);
+ dist = 10;
+ }
+ }
+ break;
+
+ case QMetaType::QObjectStar:
+ if (type == QObj) {
+ QtInstance* qtinst = QtInstance::getInstance(object);
+ if (qtinst) {
+ if (qtinst->getObject()) {
+ qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
+ ret = qVariantFromValue(qtinst->getObject());
+ qConvDebug() << ret;
+ dist = 0;
+ } else {
+ qConvDebug() << "can't convert deleted qobject";
+ }
+ } else {
+ qConvDebug() << "wasn't a qtinstance";
+ }
+ } else if (type == Null) {
+ QObject* nullobj = 0;
+ ret = qVariantFromValue(nullobj);
+ dist = 0;
+ } else {
+ qConvDebug() << "previous type was not an object:" << type;
+ }
+ break;
+
+ case QMetaType::VoidStar:
+ if (type == QObj) {
+ QtInstance* qtinst = QtInstance::getInstance(object);
+ if (qtinst) {
+ if (qtinst->getObject()) {
+ qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
+ ret = qVariantFromValue((void *)qtinst->getObject());
+ qConvDebug() << ret;
+ dist = 0;
+ } else {
+ qConvDebug() << "can't convert deleted qobject";
+ }
+ } else {
+ qConvDebug() << "wasn't a qtinstance";
+ }
+ } else if (type == Null) {
+ ret = qVariantFromValue((void*)0);
+ dist = 0;
+ } else if (type == Number) {
+ // I don't think that converting a double to a pointer is a wise
+ // move. Except maybe 0.
+ qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
+ } else {
+ qConvDebug() << "void* - unhandled type" << type;
+ }
+ break;
+
+ default:
+ // Non const type ids
+ if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
+ {
+ if (type == RTArray) {
+ RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
+
+ QObjectList result;
+ int len = rtarray->getLength();
+ for (int i = 0; i < len; ++i) {
+ JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
+ int itemdist = -1;
+ QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
+ if (itemdist >= 0)
+ result.append(item.value<QObject*>());
+ else
+ break;
+ }
+ // If we didn't fail conversion
+ if (result.count() == len) {
+ dist = 5;
+ ret = QVariant::fromValue(result);
+ }
+ } else if (type == Array) {
+ JSObject* object = value.toObject(exec);
+ JSArray* array = static_cast<JSArray *>(object);
+ QObjectList result;
+ int len = array->length();
+ for (int i = 0; i < len; ++i) {
+ JSValue val = array->get(exec, i);
+ int itemdist = -1;
+ QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
+ if (itemdist >= 0)
+ result.append(item.value<QObject*>());
+ else
+ break;
+ }
+ // If we didn't fail conversion
+ if (result.count() == len) {
+ dist = 5;
+ ret = QVariant::fromValue(result);
+ }
+ } else {
+ // Make a single length array
+ QObjectList result;
+ int itemdist = -1;
+ QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
+ if (itemdist >= 0) {
+ result.append(item.value<QObject*>());
+ dist = 10;
+ ret = QVariant::fromValue(result);
+ }
+ }
+ break;
+ } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
+ if (type == RTArray) {
+ RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
+
+ QList<int> result;
+ int len = rtarray->getLength();
+ for (int i = 0; i < len; ++i) {
+ JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
+ int itemdist = -1;
+ QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
+ if (itemdist >= 0)
+ result.append(item.value<int>());
+ else
+ break;
+ }
+ // If we didn't fail conversion
+ if (result.count() == len) {
+ dist = 5;
+ ret = QVariant::fromValue(result);
+ }
+ } else if (type == Array) {
+ JSArray* array = static_cast<JSArray *>(object);
+
+ QList<int> result;
+ int len = array->length();
+ for (int i = 0; i < len; ++i) {
+ JSValue val = array->get(exec, i);
+ int itemdist = -1;
+ QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
+ if (itemdist >= 0)
+ result.append(item.value<int>());
+ else
+ break;
+ }
+ // If we didn't fail conversion
+ if (result.count() == len) {
+ dist = 5;
+ ret = QVariant::fromValue(result);
+ }
+ } else {
+ // Make a single length array
+ QList<int> result;
+ int itemdist = -1;
+ QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
+ if (itemdist >= 0) {
+ result.append(item.value<int>());
+ dist = 10;
+ ret = QVariant::fromValue(result);
+ }
+ }
+ break;
+ } else if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(hint))) {
+ ret = QtPixmapInstance::variantFromObject(object, static_cast<QMetaType::Type>(hint));
+ } else if (hint == (QMetaType::Type) qMetaTypeId<QWebElement>()) {
+ if (object && object->inherits(&JSHTMLElement::s_info))
+ ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSHTMLElement*>(object))->impl()));
+ else if (object && object->inherits(&JSDocument::s_info))
+ ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSDocument*>(object))->impl()->documentElement()));
+ else
+ ret = QVariant::fromValue<QWebElement>(QWebElement());
+ } else if (hint == (QMetaType::Type) qMetaTypeId<QDRTNode>()) {
+ if (object && object->inherits(&JSNode::s_info))
+ ret = QVariant::fromValue<QDRTNode>(QtDRTNodeRuntime::create((static_cast<JSNode*>(object))->impl()));
+ } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
+ if (value.isUndefinedOrNull()) {
+ if (distance)
+ *distance = 1;
+ return QVariant();
+ } else {
+ if (type == Object) {
+ // Since we haven't really visited this object yet, we remove it
+ visitedObjects->remove(object);
+ }
+
+ // And then recurse with the autodetect flag
+ ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects, recursionLimit);
+ dist = 10;
+ }
+ break;
+ }
+
+ dist = 10;
+ break;
+ }
+
+ if (!ret.isValid())
+ dist = -1;
+ if (distance)
+ *distance = dist;
+
+ return ret;
+}
+
+QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance)
+{
+ const int recursionLimit = 200;
+ HashSet<JSObject*> visitedObjects;
+ return convertValueToQVariant(exec, value, hint, distance, &visitedObjects, recursionLimit);
+}
+
+JSValue convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
+{
+ // Variants with QObject * can be isNull but not a null pointer
+ // An empty QString variant is also null
+ QMetaType::Type type = (QMetaType::Type) variant.userType();
+
+ qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
+ if (variant.isNull() &&
+ type != QMetaType::QObjectStar &&
+ type != QMetaType::VoidStar &&
+ type != QMetaType::QWidgetStar &&
+ type != QMetaType::QString) {
+ return jsNull();
+ }
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ if (type == QMetaType::Bool)
+ return jsBoolean(variant.toBool());
+
+ if (type == QMetaType::Int ||
+ type == QMetaType::UInt ||
+ type == QMetaType::Long ||
+ type == QMetaType::ULong ||
+ type == QMetaType::LongLong ||
+ type == QMetaType::ULongLong ||
+ type == QMetaType::Short ||
+ type == QMetaType::UShort ||
+ type == QMetaType::Float ||
+ type == QMetaType::Double)
+ return jsNumber(variant.toDouble());
+
+ if (type == QMetaType::QRegExp) {
+ QRegExp re = variant.value<QRegExp>();
+
+ if (re.isValid()) {
+ UString uflags;
+ if (re.caseSensitivity() == Qt::CaseInsensitive)
+ uflags = "i"; // ### Can't do g or m
+
+ UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
+
+ RefPtr<JSC::RegExp> regExp = JSC::RegExp::create(&exec->globalData(), pattern, uflags);
+ if (regExp->isValid())
+ return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
+ else
+ return jsNull();
+ }
+ }
+
+ if (type == QMetaType::QDateTime ||
+ type == QMetaType::QDate ||
+ type == QMetaType::QTime) {
+
+ QDate date = QDate::currentDate();
+ QTime time(0,0,0); // midnight
+
+ if (type == QMetaType::QDate)
+ date = variant.value<QDate>();
+ else if (type == QMetaType::QTime)
+ time = variant.value<QTime>();
+ else {
+ QDateTime dt = variant.value<QDateTime>().toLocalTime();
+ date = dt.date();
+ time = dt.time();
+ }
+
+ // Dates specified this way are in local time (we convert DateTimes above)
+ GregorianDateTime dt;
+ dt.year = date.year() - 1900;
+ dt.month = date.month() - 1;
+ dt.monthDay = date.day();
+ dt.hour = time.hour();
+ dt.minute = time.minute();
+ dt.second = time.second();
+ dt.isDST = -1;
+ double ms = gregorianDateTimeToMS(exec, dt, time.msec(), /*inputIsUTC*/ false);
+
+ return new (exec) DateInstance(exec, trunc(ms));
+ }
+
+ if (type == QMetaType::QByteArray) {
+ QByteArray qtByteArray = variant.value<QByteArray>();
+ WTF::RefPtr<WTF::ByteArray> wtfByteArray = WTF::ByteArray::create(qtByteArray.length());
+ memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
+ return new (exec) JSC::JSByteArray(exec, JSC::JSByteArray::createStructure(jsNull()), wtfByteArray.get());
+ }
+
+ if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
+ QObject* obj = variant.value<QObject*>();
+ if (!obj)
+ return jsNull();
+ return QtInstance::getQtInstance(obj, root, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
+ }
+
+ if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(variant.type())))
+ return QtPixmapInstance::createPixmapRuntimeObject(exec, root, variant);
+
+ if (type == qMetaTypeId<QWebElement>()) {
+ if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
+ return jsUndefined();
+
+ Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
+ if (!document)
+ return jsUndefined();
+
+ return toJS(exec, toJSDOMGlobalObject(document, exec), QtWebElementRuntime::get(variant.value<QWebElement>()));
+ }
+
+ if (type == qMetaTypeId<QDRTNode>()) {
+ if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
+ return jsUndefined();
+
+ Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
+ if (!document)
+ return jsUndefined();
+
+ return toJS(exec, toJSDOMGlobalObject(document, exec), QtDRTNodeRuntime::get(variant.value<QDRTNode>()));
+ }
+
+ if (type == QMetaType::QVariantMap) {
+ // create a new object, and stuff properties into it
+ JSObject* ret = constructEmptyObject(exec);
+ QVariantMap map = variant.value<QVariantMap>();
+ QVariantMap::const_iterator i = map.constBegin();
+ while (i != map.constEnd()) {
+ QString s = i.key();
+ JSValue val = convertQVariantToValue(exec, root.get(), i.value());
+ if (val) {
+ PutPropertySlot slot;
+ ret->put(exec, Identifier(exec, reinterpret_cast_ptr<const UChar *>(s.constData()), s.length()), val, slot);
+ // ### error case?
+ }
+ ++i;
+ }
+
+ return ret;
+ }
+
+ // List types
+ if (type == QMetaType::QVariantList) {
+ QVariantList vl = variant.toList();
+ qConvDebug() << "got a " << vl.count() << " length list:" << vl;
+ return new (exec) RuntimeArray(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
+ } else if (type == QMetaType::QStringList) {
+ QStringList sl = variant.value<QStringList>();
+ return new (exec) RuntimeArray(exec, new QtArray<QString>(sl, QMetaType::QString, root));
+ } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
+ QObjectList ol= variant.value<QObjectList>();
+ return new (exec) RuntimeArray(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
+ } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
+ QList<int> il= variant.value<QList<int> >();
+ return new (exec) RuntimeArray(exec, new QtArray<int>(il, QMetaType::Int, root));
+ }
+
+ if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
+ QVariant real = variant.value<QVariant>();
+ qConvDebug() << "real variant is:" << real;
+ return convertQVariantToValue(exec, root, real);
+ }
+
+ qConvDebug() << "fallback path for" << variant << variant.userType();
+
+ QString string = variant.toString();
+ UString ustring((UChar*)string.utf16(), string.length());
+ return jsString(exec, ustring);
+}
+
+// ===============
+
+// Qt-like macros
+#define QW_D(Class) Class##Data* d = d_func()
+#define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
+
+const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", 0, 0, 0 };
+
+QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst)
+ : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject(), deprecatedGetDOMStructure<QtRuntimeMethod>(exec), ident)
+ , d_ptr(dd)
+{
+ QW_D(QtRuntimeMethod);
+ d->m_instance = inst;
+}
+
+QtRuntimeMethod::~QtRuntimeMethod()
+{
+ QW_D(QtRuntimeMethod);
+ d->m_instance->removeCachedMethod(this);
+ delete d_ptr;
+}
+
+// ===============
+
+QtRuntimeMethodData::~QtRuntimeMethodData()
+{
+}
+
+QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
+{
+
+}
+
+QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
+{
+
+}
+
+// ===============
+
+// Type conversion metadata (from QtScript originally)
+class QtMethodMatchType
+{
+public:
+ enum Kind {
+ Invalid,
+ Variant,
+ MetaType,
+ Unresolved,
+ MetaEnum
+ };
+
+
+ QtMethodMatchType()
+ : m_kind(Invalid) { }
+
+ Kind kind() const
+ { return m_kind; }
+
+ QMetaType::Type typeId() const;
+
+ bool isValid() const
+ { return (m_kind != Invalid); }
+
+ bool isVariant() const
+ { return (m_kind == Variant); }
+
+ bool isMetaType() const
+ { return (m_kind == MetaType); }
+
+ bool isUnresolved() const
+ { return (m_kind == Unresolved); }
+
+ bool isMetaEnum() const
+ { return (m_kind == MetaEnum); }
+
+ QByteArray name() const;
+
+ int enumeratorIndex() const
+ { Q_ASSERT(isMetaEnum()); return m_typeId; }
+
+ static QtMethodMatchType variant()
+ { return QtMethodMatchType(Variant); }
+
+ static QtMethodMatchType metaType(int typeId, const QByteArray &name)
+ { return QtMethodMatchType(MetaType, typeId, name); }
+
+ static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
+ { return QtMethodMatchType(MetaEnum, enumIndex, name); }
+
+ static QtMethodMatchType unresolved(const QByteArray &name)
+ { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
+
+private:
+ QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
+ : m_kind(kind), m_typeId(typeId), m_name(name) { }
+
+ Kind m_kind;
+ int m_typeId;
+ QByteArray m_name;
+};
+
+QMetaType::Type QtMethodMatchType::typeId() const
+{
+ if (isVariant())
+ return (QMetaType::Type) QMetaType::type("QVariant");
+ return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
+}
+
+QByteArray QtMethodMatchType::name() const
+{
+ if (!m_name.isEmpty())
+ return m_name;
+ else if (m_kind == Variant)
+ return "QVariant";
+ return QByteArray();
+}
+
+struct QtMethodMatchData
+{
+ int matchDistance;
+ int index;
+ QVector<QtMethodMatchType> types;
+ QVarLengthArray<QVariant, 10> args;
+
+ QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
+ const QVarLengthArray<QVariant, 10> &as)
+ : matchDistance(dist), index(idx), types(typs), args(as) { }
+ QtMethodMatchData()
+ : index(-1) { }
+
+ bool isValid() const
+ { return (index != -1); }
+
+ int firstUnresolvedIndex() const
+ {
+ for (int i=0; i < types.count(); i++) {
+ if (types.at(i).isUnresolved())
+ return i;
+ }
+ return -1;
+ }
+};
+
+static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
+{
+ QByteArray scope;
+ QByteArray name;
+ int scopeIdx = str.indexOf("::");
+ if (scopeIdx != -1) {
+ scope = str.left(scopeIdx);
+ name = str.mid(scopeIdx + 2);
+ } else {
+ name = str;
+ }
+ for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
+ QMetaEnum m = meta->enumerator(i);
+ if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
+ return i;
+ }
+ return -1;
+}
+
+// Helper function for resolving methods
+// Largely based on code in QtScript for compatibility reasons
+static int findMethodIndex(ExecState* exec,
+ const QMetaObject* meta,
+ const QByteArray& signature,
+ bool allowPrivate,
+ QVarLengthArray<QVariant, 10> &vars,
+ void** vvars,
+ JSObject **pError)
+{
+ QList<int> matchingIndices;
+
+ bool overloads = !signature.contains('(');
+
+ int count = meta->methodCount();
+ for (int i = count - 1; i >= 0; --i) {
+ const QMetaMethod m = meta->method(i);
+
+ // Don't choose private methods
+ if (m.access() == QMetaMethod::Private && !allowPrivate)
+ continue;
+
+ // try and find all matching named methods
+ if (m.signature() == signature)
+ matchingIndices.append(i);
+ else if (overloads) {
+ QByteArray rawsignature = m.signature();
+ rawsignature.truncate(rawsignature.indexOf('('));
+ if (rawsignature == signature)
+ matchingIndices.append(i);
+ }
+ }
+
+ int chosenIndex = -1;
+ *pError = 0;
+ QVector<QtMethodMatchType> chosenTypes;
+
+ QVarLengthArray<QVariant, 10> args;
+ QVector<QtMethodMatchData> candidates;
+ QVector<QtMethodMatchData> unresolved;
+ QVector<int> tooFewArgs;
+ QVector<int> conversionFailed;
+
+ foreach(int index, matchingIndices) {
+ QMetaMethod method = meta->method(index);
+
+ QVector<QtMethodMatchType> types;
+ bool unresolvedTypes = false;
+
+ // resolve return type
+ QByteArray returnTypeName = method.typeName();
+ int rtype = QMetaType::type(returnTypeName);
+ if ((rtype == 0) && !returnTypeName.isEmpty()) {
+ if (returnTypeName == "QVariant") {
+ types.append(QtMethodMatchType::variant());
+ } else if (returnTypeName.endsWith('*')) {
+ types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
+ } else {
+ int enumIndex = indexOfMetaEnum(meta, returnTypeName);
+ if (enumIndex != -1)
+ types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
+ else {
+ unresolvedTypes = true;
+ types.append(QtMethodMatchType::unresolved(returnTypeName));
+ }
+ }
+ } else {
+ if (returnTypeName == "QVariant")
+ types.append(QtMethodMatchType::variant());
+ else
+ types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
+ }
+
+ // resolve argument types
+ QList<QByteArray> parameterTypeNames = method.parameterTypes();
+ for (int i = 0; i < parameterTypeNames.count(); ++i) {
+ QByteArray argTypeName = parameterTypeNames.at(i);
+ int atype = QMetaType::type(argTypeName);
+ if (atype == 0) {
+ if (argTypeName == "QVariant") {
+ types.append(QtMethodMatchType::variant());
+ } else {
+ int enumIndex = indexOfMetaEnum(meta, argTypeName);
+ if (enumIndex != -1)
+ types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
+ else {
+ unresolvedTypes = true;
+ types.append(QtMethodMatchType::unresolved(argTypeName));
+ }
+ }
+ } else {
+ if (argTypeName == "QVariant")
+ types.append(QtMethodMatchType::variant());
+ else
+ types.append(QtMethodMatchType::metaType(atype, argTypeName));
+ }
+ }
+
+ // If the native method requires more arguments than what was passed from JavaScript
+ if (exec->argumentCount() + 1 < static_cast<unsigned>(types.count())) {
+ qMatchDebug() << "Match:too few args for" << method.signature();
+ tooFewArgs.append(index);
+ continue;
+ }
+
+ if (unresolvedTypes) {
+ qMatchDebug() << "Match:unresolved arg types for" << method.signature();
+ // remember it so we can give an error message later, if necessary
+ unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
+ types, QVarLengthArray<QVariant, 10>()));
+ continue;
+ }
+
+ // Now convert arguments
+ if (args.count() != types.count())
+ args.resize(types.count());
+
+ QtMethodMatchType retType = types[0];
+ args[0] = QVariant(retType.typeId(), (void *)0); // the return value
+
+ bool converted = true;
+ int matchDistance = 0;
+ for (unsigned i = 0; converted && i + 1 < static_cast<unsigned>(types.count()); ++i) {
+ JSValue arg = i < exec->argumentCount() ? exec->argument(i) : jsUndefined();
+
+ int argdistance = -1;
+ QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
+ if (argdistance >= 0) {
+ matchDistance += argdistance;
+ args[i+1] = v;
+ } else {
+ qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
+ converted = false;
+ }
+ }
+
+ qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
+
+ if (converted) {
+ if ((exec->argumentCount() + 1 == static_cast<unsigned>(types.count()))
+ && (matchDistance == 0)) {
+ // perfect match, use this one
+ chosenIndex = index;
+ break;
+ } else {
+ QtMethodMatchData currentMatch(matchDistance, index, types, args);
+ if (candidates.isEmpty()) {
+ candidates.append(currentMatch);
+ } else {
+ QtMethodMatchData bestMatchSoFar = candidates.at(0);
+ if ((args.count() > bestMatchSoFar.args.count())
+ || ((args.count() == bestMatchSoFar.args.count())
+ && (matchDistance <= bestMatchSoFar.matchDistance))) {
+ candidates.prepend(currentMatch);
+ } else {
+ candidates.append(currentMatch);
+ }
+ }
+ }
+ } else {
+ conversionFailed.append(index);
+ }
+
+ if (!overloads)
+ break;
+ }
+
+ if (chosenIndex == -1 && candidates.count() == 0) {
+ // No valid functions at all - format an error message
+ if (!conversionFailed.isEmpty()) {
+ QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
+ .arg(QLatin1String(signature));
+ for (int i = 0; i < conversionFailed.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = meta->method(conversionFailed.at(i));
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
+ } else if (!unresolved.isEmpty()) {
+ QtMethodMatchData argsInstance = unresolved.first();
+ int unresolvedIndex = argsInstance.firstUnresolvedIndex();
+ Q_ASSERT(unresolvedIndex != -1);
+ QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
+ QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
+ .arg(QString::fromLatin1(signature))
+ .arg(QLatin1String(unresolvedType.name()));
+ *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
+ } else {
+ QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
+ .arg(QLatin1String(signature));
+ for (int i = 0; i < tooFewArgs.size(); ++i) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = meta->method(tooFewArgs.at(i));
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ *pError = throwError(exec, createSyntaxError(exec, message.toLatin1().constData()));
+ }
+ }
+
+ if (chosenIndex == -1 && candidates.count() > 0) {
+ QtMethodMatchData bestMatch = candidates.at(0);
+ if ((candidates.size() > 1)
+ && (bestMatch.args.count() == candidates.at(1).args.count())
+ && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
+ // ambiguous call
+ QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
+ .arg(QLatin1String(signature));
+ for (int i = 0; i < candidates.size(); ++i) {
+ // Only candidate for overload if argument count and match distance is same as best match
+ if (candidates.at(i).args.count() == bestMatch.args.count()
+ || candidates.at(i).matchDistance == bestMatch.matchDistance) {
+ if (i > 0)
+ message += QLatin1String("\n");
+ QMetaMethod mtd = meta->method(candidates.at(i).index);
+ message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
+ }
+ }
+ *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
+ } else {
+ chosenIndex = bestMatch.index;
+ args = bestMatch.args;
+ }
+ }
+
+ if (chosenIndex != -1) {
+ /* Copy the stuff over */
+ int i;
+ vars.resize(args.count());
+ for (i=0; i < args.count(); i++) {
+ vars[i] = args[i];
+ vvars[i] = vars[i].data();
+ }
+ }
+
+ return chosenIndex;
+}
+
+// Signals are not fuzzy matched as much as methods
+static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
+{
+ int index = initialIndex;
+ QMetaMethod method = meta->method(index);
+ bool overloads = !signature.contains('(');
+ if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
+ // find the most general method
+ do {
+ method = meta->method(--index);
+ } while (method.attributes() & QMetaMethod::Cloned);
+ }
+ return index;
+}
+
+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);
+ d->m_signature = signature;
+ d->m_index = index;
+ d->m_connect = 0;
+ d->m_disconnect = 0;
+ d->m_allowPrivate = allowPrivate;
+}
+
+void QtRuntimeMetaMethod::markChildren(MarkStack& markStack)
+{
+ QtRuntimeMethod::markChildren(markStack);
+ QW_D(QtRuntimeMetaMethod);
+ if (d->m_connect)
+ markStack.append(d->m_connect);
+ if (d->m_disconnect)
+ markStack.append(d->m_disconnect);
+}
+
+EncodedJSValue QtRuntimeMetaMethod::call(ExecState* exec)
+{
+ QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(exec->callee())->d_func();
+
+ // We're limited to 10 args
+ if (exec->argumentCount() > 10)
+ return JSValue::encode(jsUndefined());
+
+ // We have to pick a method that matches..
+ JSLock lock(SilenceAssertionsOnly);
+
+ QObject *obj = d->m_instance->getObject();
+ if (obj) {
+ QVarLengthArray<QVariant, 10> vargs;
+ void *qargs[11];
+
+ int methodIndex;
+ JSObject* errorObj = 0;
+ if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, vargs, (void **)qargs, &errorObj)) != -1) {
+ if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
+ return JSValue::encode(jsUndefined());
+
+ if (vargs[0].isValid())
+ return JSValue::encode(convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]));
+ }
+
+ if (errorObj)
+ return JSValue::encode(errorObj);
+ } else {
+ return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
+ }
+
+ // void functions return undefined
+ return JSValue::encode(jsUndefined());
+}
+
+CallType QtRuntimeMetaMethod::getCallData(CallData& callData)
+{
+ callData.native.function = call;
+ return CallTypeHost;
+}
+
+bool QtRuntimeMetaMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (propertyName == "connect") {
+ slot.setCustom(this, connectGetter);
+ return true;
+ } else if (propertyName == "disconnect") {
+ slot.setCustom(this, disconnectGetter);
+ return true;
+ } else if (propertyName == exec->propertyNames().length) {
+ slot.setCustom(this, lengthGetter);
+ return true;
+ }
+
+ return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+bool QtRuntimeMetaMethod::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ if (propertyName == "connect") {
+ PropertySlot slot;
+ slot.setCustom(this, connectGetter);
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
+ return true;
+ }
+
+ if (propertyName == "disconnect") {
+ PropertySlot slot;
+ slot.setCustom(this, disconnectGetter);
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().length) {
+ PropertySlot slot;
+ slot.setCustom(this, lengthGetter);
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
+ return true;
+ }
+
+ return QtRuntimeMethod::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+}
+
+void QtRuntimeMetaMethod::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ if (mode == IncludeDontEnumProperties) {
+ propertyNames.add(Identifier(exec, "connect"));
+ propertyNames.add(Identifier(exec, "disconnect"));
+ propertyNames.add(exec->propertyNames().length);
+ }
+
+ QtRuntimeMethod::getOwnPropertyNames(exec, propertyNames, mode);
+}
+
+JSValue QtRuntimeMetaMethod::lengthGetter(ExecState*, JSValue, const Identifier&)
+{
+ // QtScript always returns 0
+ return jsNumber(0);
+}
+
+JSValue QtRuntimeMetaMethod::connectGetter(ExecState* exec, JSValue slotBase, const Identifier& ident)
+{
+ QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
+ QW_DS(QtRuntimeMetaMethod, thisObj);
+
+ if (!d->m_connect)
+ d->m_connect = new (exec) QtRuntimeConnectionMethod(exec, ident, true, d->m_instance, d->m_index, d->m_signature);
+ return d->m_connect;
+}
+
+JSValue QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, JSValue slotBase, const Identifier& ident)
+{
+ QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
+ QW_DS(QtRuntimeMetaMethod, thisObj);
+
+ if (!d->m_disconnect)
+ d->m_disconnect = new (exec) QtRuntimeConnectionMethod(exec, ident, false, d->m_instance, d->m_index, d->m_signature);
+ return d->m_disconnect;
+}
+
+// ===============
+
+QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
+
+QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, const Identifier& ident, bool isConnect, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature)
+ : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, ident, inst)
+{
+ QW_D(QtRuntimeConnectionMethod);
+
+ d->m_signature = signature;
+ d->m_index = index;
+ d->m_isConnect = isConnect;
+}
+
+EncodedJSValue QtRuntimeConnectionMethod::call(ExecState* exec)
+{
+ QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(exec->callee())->d_func();
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ QObject* sender = d->m_instance->getObject();
+
+ if (sender) {
+
+ JSObject* thisObject = exec->lexicalGlobalObject();
+ JSObject* funcObject = 0;
+
+ // QtScript checks signalness first, arguments second
+ int signalIndex = -1;
+
+ // Make sure the initial index is a signal
+ QMetaMethod m = sender->metaObject()->method(d->m_index);
+ if (m.methodType() == QMetaMethod::Signal)
+ signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
+
+ if (signalIndex != -1) {
+ if (exec->argumentCount() == 1) {
+ funcObject = exec->argument(0).toObject(exec);
+ CallData callData;
+ if (funcObject->getCallData(callData) == CallTypeNone) {
+ if (d->m_isConnect)
+ return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
+ else
+ return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
+ }
+ } else if (exec->argumentCount() >= 2) {
+ if (exec->argument(0).isObject()) {
+ thisObject = exec->argument(0).toObject(exec);
+
+ // Get the actual function to call
+ JSObject *asObj = exec->argument(1).toObject(exec);
+ CallData callData;
+ if (asObj->getCallData(callData) != CallTypeNone) {
+ // Function version
+ funcObject = asObj;
+ } else {
+ // Convert it to a string
+ UString funcName = exec->argument(1).toString(exec);
+ Identifier funcIdent(exec, funcName);
+
+ // ### DropAllLocks
+ // This is resolved at this point in QtScript
+ JSValue val = thisObject->get(exec, funcIdent);
+ JSObject* asFuncObj = val.toObject(exec);
+
+ if (asFuncObj->getCallData(callData) != CallTypeNone) {
+ funcObject = asFuncObj;
+ } else {
+ if (d->m_isConnect)
+ return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
+ else
+ return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
+ }
+ }
+ } else {
+ if (d->m_isConnect)
+ return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: thisObject is not an object"));
+ else
+ return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: thisObject is not an object"));
+ }
+ } else {
+ if (d->m_isConnect)
+ return throwVMError(exec, createError(exec, "QtMetaMethod.connect: no arguments given"));
+ else
+ return throwVMError(exec, createError(exec, "QtMetaMethod.disconnect: no arguments given"));
+ }
+
+ if (d->m_isConnect) {
+ // to connect, we need:
+ // target object [from ctor]
+ // target signal index etc. [from ctor]
+ // receiver function [from arguments]
+ // receiver this object [from arguments]
+
+ QtConnectionObject* conn = new QtConnectionObject(d->m_instance, signalIndex, thisObject, funcObject);
+ bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
+ if (!ok) {
+ delete conn;
+ QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
+ .arg(QLatin1String(sender->metaObject()->className()))
+ .arg(QLatin1String(d->m_signature));
+ return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
+ }
+ else {
+ // Store connection
+ connections.insert(sender, conn);
+ }
+ } else {
+ // Now to find our previous connection object. Hmm.
+ QList<QtConnectionObject*> conns = connections.values(sender);
+ bool ret = false;
+
+ foreach(QtConnectionObject* conn, conns) {
+ // Is this the right connection?
+ if (conn->match(sender, signalIndex, thisObject, funcObject)) {
+ // Yep, disconnect it
+ QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
+ delete conn; // this will also remove it from the map
+ ret = true;
+ break;
+ }
+ }
+
+ if (!ret) {
+ QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
+ .arg(QLatin1String(sender->metaObject()->className()))
+ .arg(QLatin1String(d->m_signature));
+ return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
+ }
+ }
+ } else {
+ QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
+ .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
+ .arg(QLatin1String(sender->metaObject()->className()))
+ .arg(QLatin1String(d->m_signature));
+ return throwVMError(exec, createTypeError(exec, msg.toLatin1().constData()));
+ }
+ } else {
+ return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
+ }
+
+ return JSValue::encode(jsUndefined());
+}
+
+CallType QtRuntimeConnectionMethod::getCallData(CallData& callData)
+{
+ callData.native.function = call;
+ return CallTypeHost;
+}
+
+bool QtRuntimeConnectionMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (propertyName == exec->propertyNames().length) {
+ slot.setCustom(this, lengthGetter);
+ return true;
+ }
+
+ return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+bool QtRuntimeConnectionMethod::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ if (propertyName == exec->propertyNames().length) {
+ PropertySlot slot;
+ slot.setCustom(this, lengthGetter);
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
+ return true;
+ }
+
+ return QtRuntimeMethod::getOwnPropertyDescriptor(exec, propertyName, descriptor);
+}
+
+void QtRuntimeConnectionMethod::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ if (mode == IncludeDontEnumProperties)
+ propertyNames.add(exec->propertyNames().length);
+
+ QtRuntimeMethod::getOwnPropertyNames(exec, propertyNames, mode);
+}
+
+JSValue QtRuntimeConnectionMethod::lengthGetter(ExecState*, JSValue, const Identifier&)
+{
+ // we have one formal argument, and one optional
+ return jsNumber(1);
+}
+
+// ===============
+
+QtConnectionObject::QtConnectionObject(PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject)
+ : m_instance(instance)
+ , m_signalIndex(signalIndex)
+ , m_originalObject(m_instance->getObject())
+ , m_thisObject(thisObject)
+ , m_funcObject(funcObject)
+{
+ setParent(m_originalObject);
+ ASSERT(JSLock::currentThreadIsHoldingLock()); // so our ProtectedPtrs are safe
+}
+
+QtConnectionObject::~QtConnectionObject()
+{
+ // Remove us from the map of active connections
+ QtRuntimeConnectionMethod::connections.remove(m_originalObject, this);
+}
+
+static const uint qt_meta_data_QtConnectionObject[] = {
+
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 1, 10, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+
+ // slots: signature, parameters, type, tag, flags
+ 28, 27, 27, 27, 0x0a,
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_QtConnectionObject[] = {
+ "JSC::Bindings::QtConnectionObject\0\0execute()\0"
+};
+
+const QMetaObject QtConnectionObject::staticMetaObject = {
+ { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
+ qt_meta_data_QtConnectionObject, 0 }
+};
+
+const QMetaObject *QtConnectionObject::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+void *QtConnectionObject::qt_metacast(const char *_clname)
+{
+ if (!_clname) return 0;
+ if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
+ return static_cast<void*>(const_cast<QtConnectionObject*>(this));
+ return QObject::qt_metacast(_clname);
+}
+
+int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ _id = QObject::qt_metacall(_c, _id, _a);
+ if (_id < 0)
+ return _id;
+ if (_c == QMetaObject::InvokeMetaMethod) {
+ switch (_id) {
+ case 0: execute(_a); break;
+ }
+ _id -= 1;
+ }
+ return _id;
+}
+
+void QtConnectionObject::execute(void **argv)
+{
+ QObject* obj = m_instance->getObject();
+ if (obj) {
+ const QMetaObject* meta = obj->metaObject();
+ const QMetaMethod method = meta->method(m_signalIndex);
+
+ QList<QByteArray> parameterTypes = method.parameterTypes();
+
+ int argc = parameterTypes.count();
+
+ JSLock lock(SilenceAssertionsOnly);
+
+ // ### Should the Interpreter/ExecState come from somewhere else?
+ RefPtr<RootObject> ro = m_instance->rootObject();
+ if (ro) {
+ JSGlobalObject* globalobj = ro->globalObject();
+ if (globalobj) {
+ ExecState* exec = globalobj->globalExec();
+ if (exec) {
+ // Build the argument list (up to the formal argument length of the slot)
+ MarkedArgumentBuffer l;
+ // ### DropAllLocks?
+ int funcArgC = m_funcObject->get(exec, exec->propertyNames().length).toInt32(exec);
+ int argTotal = qMax(funcArgC, argc);
+ for(int i=0; i < argTotal; i++) {
+ if (i < argc) {
+ int argType = QMetaType::type(parameterTypes.at(i));
+ l.append(convertQVariantToValue(exec, ro, QVariant(argType, argv[i+1])));
+ } else {
+ l.append(jsUndefined());
+ }
+ }
+ // Stuff in the __qt_sender property, if we can
+ ScopeChain oldsc = ScopeChain(NoScopeChain());
+ JSFunction* fimp = 0;
+ if (m_funcObject->inherits(&JSFunction::info)) {
+ fimp = static_cast<JSFunction*>(m_funcObject.get());
+
+ JSObject* qt_sender = QtInstance::getQtInstance(sender(), ro, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
+ JSObject* wrapper = new (exec) JSObject(JSObject::createStructure(jsNull()));
+ PutPropertySlot slot;
+ wrapper->put(exec, Identifier(exec, "__qt_sender__"), qt_sender, slot);
+ oldsc = fimp->scope();
+ ScopeChain sc = oldsc;
+ sc.push(wrapper);
+ fimp->setScope(sc);
+ }
+
+ CallData callData;
+ CallType callType = m_funcObject->getCallData(callData);
+ call(exec, m_funcObject, callType, callData, m_thisObject, l);
+
+ if (fimp)
+ fimp->setScope(oldsc);
+ }
+ }
+ }
+ } else {
+ // A strange place to be - a deleted object emitted a signal here.
+ qWarning() << "sender deleted, cannot deliver signal";
+ }
+}
+
+bool QtConnectionObject::match(QObject* sender, int signalIndex, JSObject* thisObject, JSObject *funcObject)
+{
+ if (m_originalObject == sender && m_signalIndex == signalIndex
+ && thisObject == (JSObject*)m_thisObject && funcObject == (JSObject*)m_funcObject)
+ return true;
+ return false;
+}
+
+// ===============
+
+template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
+ : Array(rootObject)
+ , m_list(list)
+ , m_type(type)
+{
+ m_length = m_list.count();
+}
+
+template <typename T> QtArray<T>::~QtArray ()
+{
+}
+
+template <typename T> RootObject* QtArray<T>::rootObject() const
+{
+ return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
+}
+
+template <typename T> void QtArray<T>::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
+{
+ // QtScript sets the value, but doesn't forward it to the original source
+ // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
+ // copy of the list is).
+ int dist = -1;
+ QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
+
+ if (dist >= 0) {
+ m_list[index] = val.value<T>();
+ }
+}
+
+
+template <typename T> JSValue QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
+{
+ if (index < m_length) {
+ T val = m_list.at(index);
+ return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
+ }
+
+ return jsUndefined();
+}
+
+// ===============
+
+} }
diff --git a/Source/WebCore/bridge/qt/qt_runtime.h b/Source/WebCore/bridge/qt/qt_runtime.h
new file mode 100644
index 0000000..68bf865
--- /dev/null
+++ b/Source/WebCore/bridge/qt/qt_runtime.h
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef BINDINGS_QT_RUNTIME_H_
+#define BINDINGS_QT_RUNTIME_H_
+
+#include "Bridge.h"
+#include "Completion.h"
+#include "Protect.h"
+#include "runtime_method.h"
+
+#include <qbytearray.h>
+#include <qmetaobject.h>
+#include <qpointer.h>
+#include <qvariant.h>
+
+namespace JSC {
+namespace Bindings {
+
+class QtInstance;
+
+class QtField : public Field {
+public:
+
+ typedef enum {
+ MetaProperty,
+#ifndef QT_NO_PROPERTIES
+ DynamicProperty,
+#endif
+ ChildObject
+ } QtFieldType;
+
+ QtField(const QMetaProperty &p)
+ : m_type(MetaProperty), m_property(p)
+ {}
+
+#ifndef QT_NO_PROPERTIES
+ QtField(const QByteArray &b)
+ : m_type(DynamicProperty), m_dynamicProperty(b)
+ {}
+#endif
+
+ QtField(QObject *child)
+ : m_type(ChildObject), m_childObject(child)
+ {}
+
+ virtual JSValue valueFromInstance(ExecState*, const Instance*) const;
+ virtual void setValueToInstance(ExecState*, const Instance*, JSValue) const;
+ QByteArray name() const;
+ QtFieldType fieldType() const {return m_type;}
+private:
+ QtFieldType m_type;
+ QByteArray m_dynamicProperty;
+ QMetaProperty m_property;
+ QPointer<QObject> m_childObject;
+};
+
+
+class QtMethod : public Method
+{
+public:
+ QtMethod(const QMetaObject *mo, int i, const QByteArray &ident, int numParameters)
+ : m_metaObject(mo),
+ m_index(i),
+ m_identifier(ident),
+ m_nParams(numParameters)
+ { }
+
+ virtual const char* name() const { return m_identifier.constData(); }
+ virtual int numParameters() const { return m_nParams; }
+
+private:
+ friend class QtInstance;
+ const QMetaObject *m_metaObject;
+ int m_index;
+ QByteArray m_identifier;
+ int m_nParams;
+};
+
+
+template <typename T> class QtArray : public Array
+{
+public:
+ QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject>);
+ virtual ~QtArray();
+
+ RootObject* rootObject() const;
+
+ virtual void setValueAt(ExecState*, unsigned index, JSValue) const;
+ virtual JSValue valueAt(ExecState*, unsigned index) const;
+ virtual unsigned int getLength() const {return m_length;}
+
+private:
+ mutable QList<T> m_list; // setValueAt is const!
+ unsigned int m_length;
+ QMetaType::Type m_type;
+};
+
+// Based on RuntimeMethod
+
+// Extra data classes (to avoid the CELL_SIZE limit on JS objects)
+
+class QtRuntimeMethodData {
+ public:
+ virtual ~QtRuntimeMethodData();
+ RefPtr<QtInstance> m_instance;
+};
+
+class QtRuntimeConnectionMethod;
+class QtRuntimeMetaMethodData : public QtRuntimeMethodData {
+ public:
+ ~QtRuntimeMetaMethodData();
+ QByteArray m_signature;
+ bool m_allowPrivate;
+ int m_index;
+ QtRuntimeConnectionMethod *m_connect;
+ QtRuntimeConnectionMethod *m_disconnect;
+};
+
+class QtRuntimeConnectionMethodData : public QtRuntimeMethodData {
+ public:
+ ~QtRuntimeConnectionMethodData();
+ QByteArray m_signature;
+ int m_index;
+ bool m_isConnect;
+};
+
+// Common base class (doesn't really do anything interesting)
+class QtRuntimeMethod : public InternalFunction {
+public:
+ virtual ~QtRuntimeMethod();
+
+ static const ClassInfo s_info;
+
+ static FunctionPrototype* createPrototype(ExecState*, JSGlobalObject* globalObject)
+ {
+ return globalObject->functionPrototype();
+ }
+
+ static PassRefPtr<Structure> createStructure(JSValue prototype)
+ {
+ return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
+ }
+
+protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | InternalFunction::StructureFlags | OverridesMarkChildren;
+
+ QtRuntimeMethodData *d_func() const {return d_ptr;}
+ QtRuntimeMethod(QtRuntimeMethodData *dd, ExecState *exec, const Identifier &n, PassRefPtr<QtInstance> inst);
+ QtRuntimeMethodData *d_ptr;
+};
+
+class QtRuntimeMetaMethod : public QtRuntimeMethod
+{
+public:
+ QtRuntimeMetaMethod(ExecState *exec, const Identifier &n, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate);
+
+ virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
+
+ virtual void markChildren(MarkStack& markStack);
+
+protected:
+ QtRuntimeMetaMethodData* d_func() const {return reinterpret_cast<QtRuntimeMetaMethodData*>(d_ptr);}
+
+private:
+ virtual CallType getCallData(CallData&);
+ static EncodedJSValue JSC_HOST_CALL call(ExecState* exec);
+ static JSValue lengthGetter(ExecState*, JSValue, const Identifier&);
+ static JSValue connectGetter(ExecState*, JSValue, const Identifier&);
+ static JSValue disconnectGetter(ExecState*, JSValue, const Identifier&);
+};
+
+class QtConnectionObject;
+class QtRuntimeConnectionMethod : public QtRuntimeMethod
+{
+public:
+ QtRuntimeConnectionMethod(ExecState *exec, const Identifier &n, bool isConnect, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature );
+
+ virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
+ virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
+
+protected:
+ QtRuntimeConnectionMethodData* d_func() const {return reinterpret_cast<QtRuntimeConnectionMethodData*>(d_ptr);}
+
+private:
+ virtual CallType getCallData(CallData&);
+ static EncodedJSValue JSC_HOST_CALL call(ExecState* exec);
+ static JSValue lengthGetter(ExecState*, JSValue, const Identifier&);
+ static QMultiMap<QObject *, QtConnectionObject *> connections;
+ friend class QtConnectionObject;
+};
+
+class QtConnectionObject: public QObject
+{
+public:
+ QtConnectionObject(PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject);
+ ~QtConnectionObject();
+
+ static const QMetaObject staticMetaObject;
+ virtual const QMetaObject *metaObject() const;
+ virtual void *qt_metacast(const char *);
+ virtual int qt_metacall(QMetaObject::Call, int, void **argv);
+
+ bool match(QObject *sender, int signalIndex, JSObject* thisObject, JSObject *funcObject);
+
+ // actual slot:
+ void execute(void **argv);
+
+private:
+ RefPtr<QtInstance> m_instance;
+ int m_signalIndex;
+ QObject* m_originalObject; // only used as a key, not dereferenced
+ ProtectedPtr<JSObject> m_thisObject;
+ ProtectedPtr<JSObject> m_funcObject;
+};
+
+QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance);
+JSValue convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant);
+
+} // namespace Bindings
+} // namespace JSC
+
+#endif