src/script/bridge/qscriptqobject.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtScript module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "config.h"
       
    43 #include "qscriptqobject_p.h"
       
    44 
       
    45 #include <QtCore/qmetaobject.h>
       
    46 #include <QtCore/qvarlengtharray.h>
       
    47 #include <QtCore/qdebug.h>
       
    48 #include <QtScript/qscriptable.h>
       
    49 #include "../api/qscriptengine_p.h"
       
    50 #include "../api/qscriptable_p.h"
       
    51 #include "../api/qscriptcontext_p.h"
       
    52 #include "qscriptfunction_p.h"
       
    53 
       
    54 #include "Error.h"
       
    55 #include "PrototypeFunction.h"
       
    56 #include "PropertyNameArray.h"
       
    57 #include "JSFunction.h"
       
    58 #include "JSString.h"
       
    59 #include "JSValue.h"
       
    60 #include "JSArray.h"
       
    61 #include "RegExpObject.h"
       
    62 #include "RegExpConstructor.h"
       
    63 
       
    64 namespace JSC
       
    65 {
       
    66 QT_USE_NAMESPACE
       
    67 ASSERT_CLASS_FITS_IN_CELL(QScript::QObjectPrototype);
       
    68 ASSERT_CLASS_FITS_IN_CELL(QScript::QMetaObjectWrapperObject);
       
    69 ASSERT_CLASS_FITS_IN_CELL(QScript::QMetaObjectPrototype);
       
    70 ASSERT_CLASS_FITS_IN_CELL(QScript::QtFunction);
       
    71 ASSERT_CLASS_FITS_IN_CELL(QScript::QtPropertyFunction);
       
    72 }
       
    73 
       
    74 QT_BEGIN_NAMESPACE
       
    75 
       
    76 namespace QScript
       
    77 {
       
    78 
       
    79 struct QObjectConnection
       
    80 {
       
    81     int slotIndex;
       
    82     JSC::JSValue receiver;
       
    83     JSC::JSValue slot;
       
    84     JSC::JSValue senderWrapper;
       
    85 
       
    86     QObjectConnection(int i, JSC::JSValue r, JSC::JSValue s,
       
    87                       JSC::JSValue sw)
       
    88         : slotIndex(i), receiver(r), slot(s), senderWrapper(sw) {}
       
    89     QObjectConnection() : slotIndex(-1) {}
       
    90 
       
    91     bool hasTarget(JSC::JSValue r, JSC::JSValue s) const
       
    92     {
       
    93         if ((r && r.isObject()) != (receiver && receiver.isObject()))
       
    94             return false;
       
    95         if (((r && r.isObject()) && (receiver && receiver.isObject()))
       
    96             && (r != receiver)) {
       
    97             return false;
       
    98         }
       
    99         return (s == slot);
       
   100     }
       
   101 
       
   102     void mark(JSC::MarkStack& markStack)
       
   103     {
       
   104         // ### need to find out if senderWrapper is marked
       
   105         if (senderWrapper) {
       
   106             // see if the sender should be marked or not
       
   107             Q_ASSERT(senderWrapper.inherits(&QScriptObject::info));
       
   108             QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(senderWrapper));
       
   109             QScriptObjectDelegate *delegate = scriptObject->delegate();
       
   110             Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
       
   111             QObjectDelegate *inst = static_cast<QObjectDelegate*>(delegate);
       
   112             if ((inst->ownership() == QScriptEngine::ScriptOwnership)
       
   113                 || ((inst->ownership() == QScriptEngine::AutoOwnership)
       
   114                     && inst->value() && !inst->value()->parent())) {
       
   115                 // #### don't mark if not marked otherwise
       
   116                 //senderWrapper = JSC::JSValue();
       
   117                 markStack.append(senderWrapper);
       
   118             } else {
       
   119                 markStack.append(senderWrapper);
       
   120             }
       
   121         }
       
   122         if (receiver)
       
   123             markStack.append(receiver);
       
   124         if (slot)
       
   125             markStack.append(slot);
       
   126     }
       
   127 };
       
   128 
       
   129 class QObjectNotifyCaller : public QObject
       
   130 {
       
   131 public:
       
   132     void callConnectNotify(const char *signal)
       
   133         { connectNotify(signal); }
       
   134     void callDisconnectNotify(const char *signal)
       
   135         { disconnectNotify(signal); }
       
   136 };
       
   137 
       
   138 class QObjectConnectionManager: public QObject
       
   139 {
       
   140 public:
       
   141     QObjectConnectionManager(QScriptEnginePrivate *engine);
       
   142     ~QObjectConnectionManager();
       
   143 
       
   144     bool addSignalHandler(QObject *sender, int signalIndex,
       
   145                           JSC::JSValue receiver,
       
   146                           JSC::JSValue slot,
       
   147                           JSC::JSValue senderWrapper,
       
   148                           Qt::ConnectionType type);
       
   149     bool removeSignalHandler(QObject *sender, int signalIndex,
       
   150                              JSC::JSValue receiver,
       
   151                              JSC::JSValue slot);
       
   152 
       
   153     static const QMetaObject staticMetaObject;
       
   154     virtual const QMetaObject *metaObject() const;
       
   155     virtual void *qt_metacast(const char *);
       
   156     virtual int qt_metacall(QMetaObject::Call, int, void **argv);
       
   157 
       
   158     void execute(int slotIndex, void **argv);
       
   159 
       
   160     void mark(JSC::MarkStack&);
       
   161 
       
   162 private:
       
   163     QScriptEnginePrivate *engine;
       
   164     int slotCounter;
       
   165     QVector<QVector<QObjectConnection> > connections;
       
   166 };
       
   167 
       
   168 static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt)
       
   169 {
       
   170     return (method.access() != QMetaMethod::Private)
       
   171         && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater));
       
   172 }
       
   173 
       
   174 static bool isEnumerableMetaProperty(const QMetaProperty &prop,
       
   175                                      const QMetaObject *mo, int index)
       
   176 {
       
   177     return prop.isScriptable() && prop.isValid()
       
   178         // the following lookup is to ensure that we have the
       
   179         // "most derived" occurrence of the property with this name
       
   180         && (mo->indexOfProperty(prop.name()) == index);
       
   181 }
       
   182 
       
   183 static inline QByteArray methodName(const QMetaMethod &method)
       
   184 {
       
   185     QByteArray signature = method.signature();
       
   186     return signature.left(signature.indexOf('('));
       
   187 }
       
   188 
       
   189 static QVariant variantFromValue(QScriptEnginePrivate *eng,
       
   190                                  int targetType, const QScriptValue &value)
       
   191 {
       
   192     QVariant v(targetType, (void *)0);
       
   193     Q_ASSERT(eng);
       
   194     if (QScriptEnginePrivate::convert(value, targetType, v.data(), eng))
       
   195         return v;
       
   196     if (uint(targetType) == QVariant::LastType)
       
   197         return value.toVariant();
       
   198     if (value.isVariant()) {
       
   199         v = value.toVariant();
       
   200         if (v.canConvert(QVariant::Type(targetType))) {
       
   201             v.convert(QVariant::Type(targetType));
       
   202             return v;
       
   203         }
       
   204         QByteArray typeName = v.typeName();
       
   205         if (typeName.endsWith('*')
       
   206             && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
       
   207             return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
       
   208         }
       
   209     }
       
   210 
       
   211     return QVariant();
       
   212 }
       
   213 
       
   214 static const bool GeneratePropertyFunctions = true;
       
   215 
       
   216 static unsigned flagsForMetaProperty(const QMetaProperty &prop)
       
   217 {
       
   218     return (JSC::DontDelete
       
   219             | (!prop.isWritable() ? unsigned(JSC::ReadOnly) : unsigned(0))
       
   220             | (GeneratePropertyFunctions
       
   221                ? unsigned(JSC::Getter | JSC::Setter)
       
   222                   : unsigned(0))
       
   223             | QObjectMemberAttribute);
       
   224 }
       
   225 
       
   226 static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
       
   227 {
       
   228     QByteArray scope;
       
   229     QByteArray name;
       
   230     int scopeIdx = str.lastIndexOf("::");
       
   231     if (scopeIdx != -1) {
       
   232         scope = str.left(scopeIdx);
       
   233         name = str.mid(scopeIdx + 2);
       
   234     } else {
       
   235         name = str;
       
   236     }
       
   237     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
       
   238         QMetaEnum m = meta->enumerator(i);
       
   239         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
       
   240             return i;
       
   241     }
       
   242     return -1;
       
   243 }
       
   244 
       
   245 static inline QScriptable *scriptableFromQObject(QObject *qobj)
       
   246 {
       
   247     void *ptr = qobj->qt_metacast("QScriptable");
       
   248     return reinterpret_cast<QScriptable*>(ptr);
       
   249 }
       
   250 
       
   251 QtFunction::QtFunction(JSC::JSValue object, int initialIndex, bool maybeOverloaded,
       
   252                        JSC::JSGlobalData *data, WTF::PassRefPtr<JSC::Structure> sid,
       
   253                        const JSC::Identifier &ident)
       
   254     : JSC::InternalFunction(data, sid, ident),
       
   255       data(new Data(object, initialIndex, maybeOverloaded))
       
   256 {
       
   257 }
       
   258 
       
   259 QtFunction::~QtFunction()
       
   260 {
       
   261     delete data;
       
   262 }
       
   263 
       
   264 JSC::CallType QtFunction::getCallData(JSC::CallData &callData)
       
   265 {
       
   266     callData.native.function = call;
       
   267     return JSC::CallTypeHost;
       
   268 }
       
   269 
       
   270 void QtFunction::markChildren(JSC::MarkStack& markStack)
       
   271 {
       
   272     if (data->object)
       
   273         markStack.append(data->object);
       
   274     JSC::InternalFunction::markChildren(markStack);
       
   275 }
       
   276 
       
   277 QScriptObject *QtFunction::wrapperObject() const
       
   278 {
       
   279     Q_ASSERT(JSC::asObject(data->object)->inherits(&QScriptObject::info));
       
   280     return static_cast<QScriptObject*>(JSC::asObject(data->object));
       
   281 }
       
   282 
       
   283 QObject *QtFunction::qobject() const
       
   284 {
       
   285     QScriptObject *scriptObject = wrapperObject();
       
   286     QScriptObjectDelegate *delegate = scriptObject->delegate();
       
   287     Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
       
   288     return static_cast<QScript::QObjectDelegate*>(delegate)->value();
       
   289 }
       
   290 
       
   291 const QMetaObject *QtFunction::metaObject() const
       
   292 {
       
   293     QObject *qobj = qobject();
       
   294     if (!qobj)
       
   295         return 0;
       
   296     return qobj->metaObject();
       
   297 }
       
   298 
       
   299 int QtFunction::initialIndex() const
       
   300 {
       
   301     return data->initialIndex;
       
   302 }
       
   303 
       
   304 bool QtFunction::maybeOverloaded() const
       
   305 {
       
   306     return data->maybeOverloaded;
       
   307 }
       
   308 
       
   309 int QtFunction::mostGeneralMethod(QMetaMethod *out) const
       
   310 {
       
   311     const QMetaObject *meta = metaObject();
       
   312     if (!meta)
       
   313         return -1;
       
   314     int index = initialIndex();
       
   315     QMetaMethod method = meta->method(index);
       
   316     if (maybeOverloaded() && (method.attributes() & QMetaMethod::Cloned)) {
       
   317         // find the most general method
       
   318         do {
       
   319             method = meta->method(--index);
       
   320         } while (method.attributes() & QMetaMethod::Cloned);
       
   321     }
       
   322     if (out)
       
   323         *out = method;
       
   324     return index;
       
   325 }
       
   326 
       
   327 QList<int> QScript::QtFunction::overloadedIndexes() const
       
   328 {
       
   329     if (!maybeOverloaded())
       
   330         return QList<int>();
       
   331     QList<int> result;
       
   332     QString name = functionName();
       
   333     const QMetaObject *meta = metaObject();
       
   334     for (int index = mostGeneralMethod() - 1; index >= 0; --index) {
       
   335         QString otherName = QString::fromLatin1(methodName(meta->method(index)));
       
   336         if (otherName == name)
       
   337             result.append(index);
       
   338     }
       
   339     return result;
       
   340 }
       
   341 
       
   342 QString QtFunction::functionName() const
       
   343 {
       
   344     const QMetaObject *meta = metaObject();
       
   345     if (!meta)
       
   346         return QString();
       
   347     QMetaMethod method = meta->method(initialIndex());
       
   348     return QLatin1String(methodName(method));
       
   349 }
       
   350 
       
   351 class QScriptMetaType
       
   352 {
       
   353 public:
       
   354     enum Kind {
       
   355         Invalid,
       
   356         Variant,
       
   357         MetaType,
       
   358         Unresolved,
       
   359         MetaEnum
       
   360     };
       
   361 
       
   362     inline QScriptMetaType()
       
   363         : m_kind(Invalid) { }
       
   364 
       
   365     inline Kind kind() const
       
   366     { return m_kind; }
       
   367 
       
   368     int typeId() const;
       
   369 
       
   370     inline bool isValid() const
       
   371     { return (m_kind != Invalid); }
       
   372 
       
   373     inline bool isVariant() const
       
   374     { return (m_kind == Variant); }
       
   375 
       
   376     inline bool isMetaType() const
       
   377     { return (m_kind == MetaType); }
       
   378 
       
   379     inline bool isUnresolved() const
       
   380     { return (m_kind == Unresolved); }
       
   381 
       
   382     inline bool isMetaEnum() const
       
   383     { return (m_kind == MetaEnum); }
       
   384 
       
   385     QByteArray name() const;
       
   386 
       
   387     inline int enumeratorIndex() const
       
   388     { Q_ASSERT(isMetaEnum()); return m_typeId; }
       
   389 
       
   390     inline bool operator==(const QScriptMetaType &other) const
       
   391     {
       
   392         return (m_kind == other.m_kind) && (m_typeId == other.m_typeId);
       
   393     }
       
   394 
       
   395     static inline QScriptMetaType variant()
       
   396     { return QScriptMetaType(Variant); }
       
   397 
       
   398     static inline QScriptMetaType metaType(int typeId, const QByteArray &name)
       
   399     { return QScriptMetaType(MetaType, typeId, name); }
       
   400 
       
   401     static inline QScriptMetaType metaEnum(int enumIndex, const QByteArray &name)
       
   402     { return QScriptMetaType(MetaEnum, enumIndex, name); }
       
   403 
       
   404     static inline QScriptMetaType unresolved(const QByteArray &name)
       
   405     { return QScriptMetaType(Unresolved, /*typeId=*/0, name); }
       
   406 
       
   407 private:
       
   408     inline QScriptMetaType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
       
   409         : m_kind(kind), m_typeId(typeId), m_name(name) { }
       
   410 
       
   411     Kind m_kind;
       
   412     int m_typeId;
       
   413     QByteArray m_name;
       
   414 };
       
   415 
       
   416 int QScriptMetaType::typeId() const
       
   417 {
       
   418     if (isVariant())
       
   419         return QMetaType::type("QVariant");
       
   420     return isMetaEnum() ? 2/*int*/ : m_typeId;
       
   421 }
       
   422 
       
   423 QByteArray QScriptMetaType::name() const
       
   424 {
       
   425     if (!m_name.isEmpty())
       
   426         return m_name;
       
   427     else if (m_kind == Variant)
       
   428         return "QVariant";
       
   429     return QMetaType::typeName(typeId());
       
   430 }
       
   431 
       
   432 class QScriptMetaMethod
       
   433 {
       
   434 public:
       
   435     inline QScriptMetaMethod()
       
   436         { }
       
   437     inline QScriptMetaMethod(const QByteArray &name, const QVector<QScriptMetaType> &types)
       
   438         : m_name(name), m_types(types), m_firstUnresolvedIndex(-1)
       
   439     {
       
   440         QVector<QScriptMetaType>::const_iterator it;
       
   441         for (it = m_types.constBegin(); it != m_types.constEnd(); ++it) {
       
   442             if ((*it).kind() == QScriptMetaType::Unresolved) {
       
   443                 m_firstUnresolvedIndex = it - m_types.constBegin();
       
   444                 break;
       
   445             }
       
   446         }
       
   447     }
       
   448     inline bool isValid() const
       
   449     { return !m_types.isEmpty(); }
       
   450 
       
   451     QByteArray name() const
       
   452     { return m_name; }
       
   453 
       
   454     inline QScriptMetaType returnType() const
       
   455     { return m_types.at(0); }
       
   456 
       
   457     inline int argumentCount() const
       
   458     { return m_types.count() - 1; }
       
   459 
       
   460     inline QScriptMetaType argumentType(int arg) const
       
   461     { return m_types.at(arg + 1); }
       
   462 
       
   463     inline bool fullyResolved() const
       
   464     { return m_firstUnresolvedIndex == -1; }
       
   465 
       
   466     inline bool hasUnresolvedReturnType() const
       
   467     { return (m_firstUnresolvedIndex == 0); }
       
   468 
       
   469     inline int firstUnresolvedIndex() const
       
   470     { return m_firstUnresolvedIndex; }
       
   471 
       
   472     inline int count() const
       
   473     { return m_types.count(); }
       
   474 
       
   475     inline QScriptMetaType type(int index) const
       
   476     { return m_types.at(index); }
       
   477 
       
   478     inline QVector<QScriptMetaType> types() const
       
   479     { return m_types; }
       
   480 
       
   481 private:
       
   482     QByteArray m_name;
       
   483     QVector<QScriptMetaType> m_types;
       
   484     int m_firstUnresolvedIndex;
       
   485 };
       
   486 
       
   487 struct QScriptMetaArguments
       
   488 {
       
   489     int matchDistance;
       
   490     int index;
       
   491     QScriptMetaMethod method;
       
   492     QVarLengthArray<QVariant, 9> args;
       
   493 
       
   494     inline QScriptMetaArguments(int dist, int idx, const QScriptMetaMethod &mtd,
       
   495                                 const QVarLengthArray<QVariant, 9> &as)
       
   496         : matchDistance(dist), index(idx), method(mtd), args(as) { }
       
   497     inline QScriptMetaArguments()
       
   498         : index(-1) { }
       
   499 
       
   500     inline bool isValid() const
       
   501     { return (index != -1); }
       
   502 };
       
   503 
       
   504 static QMetaMethod metaMethod(const QMetaObject *meta,
       
   505                               QMetaMethod::MethodType type,
       
   506                               int index)
       
   507 {
       
   508     if (type != QMetaMethod::Constructor)
       
   509         return meta->method(index);
       
   510     else
       
   511         return meta->constructor(index);
       
   512 }
       
   513     
       
   514 static JSC::JSValue callQtMethod(JSC::ExecState *exec, QMetaMethod::MethodType callType,
       
   515                                  QObject *thisQObject, const JSC::ArgList &scriptArgs,
       
   516                                  const QMetaObject *meta, int initialIndex,
       
   517                                  bool maybeOverloaded)
       
   518 {
       
   519     QByteArray funName;
       
   520     QScriptMetaMethod chosenMethod;
       
   521     int chosenIndex = -1;
       
   522     QVarLengthArray<QVariant, 9> args;
       
   523     QVector<QScriptMetaArguments> candidates;
       
   524     QVector<QScriptMetaArguments> unresolved;
       
   525     QVector<int> tooFewArgs;
       
   526     QVector<int> conversionFailed;
       
   527     int index;
       
   528     exec->clearException();
       
   529     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(exec);
       
   530     for (index = initialIndex; index >= 0; --index) {
       
   531         QMetaMethod method = metaMethod(meta, callType, index);
       
   532 
       
   533         if (index == initialIndex)
       
   534             funName = methodName(method);
       
   535         else {
       
   536             if (methodName(method) != funName)
       
   537                 continue;
       
   538         }
       
   539 
       
   540         QVector<QScriptMetaType> types;
       
   541         // resolve return type
       
   542         QByteArray returnTypeName = method.typeName();
       
   543         int rtype = QMetaType::type(returnTypeName);
       
   544         if ((rtype == 0) && !returnTypeName.isEmpty()) {
       
   545             if (returnTypeName == "QVariant") {
       
   546                 types.append(QScriptMetaType::variant());
       
   547             } else {
       
   548                 int enumIndex = indexOfMetaEnum(meta, returnTypeName);
       
   549                 if (enumIndex != -1)
       
   550                     types.append(QScriptMetaType::metaEnum(enumIndex, returnTypeName));
       
   551                 else
       
   552                     types.append(QScriptMetaType::unresolved(returnTypeName));
       
   553             }
       
   554         } else {
       
   555             if (callType == QMetaMethod::Constructor)
       
   556                 types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*"));
       
   557             else if (returnTypeName == "QVariant")
       
   558                 types.append(QScriptMetaType::variant());
       
   559             else
       
   560                 types.append(QScriptMetaType::metaType(rtype, returnTypeName));
       
   561         }
       
   562 
       
   563         // resolve argument types
       
   564         QList<QByteArray> parameterTypeNames = method.parameterTypes();
       
   565         for (int i = 0; i < parameterTypeNames.count(); ++i) {
       
   566             QByteArray argTypeName = parameterTypeNames.at(i);
       
   567             int atype = QMetaType::type(argTypeName);
       
   568             if (atype == 0) {
       
   569                 if (argTypeName == "QVariant") {
       
   570                     types.append(QScriptMetaType::variant());
       
   571                 } else {
       
   572                     int enumIndex = indexOfMetaEnum(meta, argTypeName);
       
   573                     if (enumIndex != -1)
       
   574                         types.append(QScriptMetaType::metaEnum(enumIndex, argTypeName));
       
   575                     else
       
   576                         types.append(QScriptMetaType::unresolved(argTypeName));
       
   577                 }
       
   578             } else {
       
   579                 if (argTypeName == "QVariant")
       
   580                     types.append(QScriptMetaType::variant());
       
   581                 else
       
   582                     types.append(QScriptMetaType::metaType(atype, argTypeName));
       
   583             }
       
   584         }
       
   585 
       
   586         QScriptMetaMethod mtd = QScriptMetaMethod(methodName(method), types);
       
   587 
       
   588         if (int(scriptArgs.size()) < mtd.argumentCount()) {
       
   589             tooFewArgs.append(index);
       
   590             continue;
       
   591         }
       
   592 
       
   593         if (!mtd.fullyResolved()) {
       
   594             // remember it so we can give an error message later, if necessary
       
   595             unresolved.append(QScriptMetaArguments(/*matchDistance=*/INT_MAX, index,
       
   596                                                    mtd, QVarLengthArray<QVariant, 9>()));
       
   597             if (mtd.hasUnresolvedReturnType())
       
   598                 continue;
       
   599         }
       
   600 
       
   601         if (args.count() != mtd.count())
       
   602             args.resize(mtd.count());
       
   603 
       
   604         QScriptMetaType retType = mtd.returnType();
       
   605         args[0] = QVariant(retType.typeId(), (void *)0); // the result
       
   606 
       
   607         // try to convert arguments
       
   608         bool converted = true;
       
   609         int matchDistance = 0;
       
   610         for (int i = 0; converted && i < mtd.argumentCount(); ++i) {
       
   611             QScriptValue actual;
       
   612             if (i < (int)scriptArgs.size())
       
   613                 actual = engine->scriptValueFromJSCValue(scriptArgs.at(i));
       
   614             else
       
   615                 actual = QScriptValue(QScriptValue::UndefinedValue);
       
   616             QScriptMetaType argType = mtd.argumentType(i);
       
   617             int tid = -1;
       
   618             QVariant v;
       
   619             if (argType.isUnresolved()) {
       
   620                 v = QVariant(QMetaType::QObjectStar, (void *)0);
       
   621                 converted = engine->convertToNativeQObject(
       
   622                     actual, argType.name(), reinterpret_cast<void* *>(v.data()));
       
   623             } else if (argType.isVariant()) {
       
   624                 if (actual.isVariant()) {
       
   625                     v = actual.toVariant();
       
   626                 } else {
       
   627                     v = actual.toVariant();
       
   628                     converted = v.isValid() || actual.isUndefined() || actual.isNull();
       
   629                 }
       
   630             } else {
       
   631                 tid = argType.typeId();
       
   632                 v = QVariant(tid, (void *)0);
       
   633                 converted = QScriptEnginePrivate::convert(actual, tid, v.data(), engine);
       
   634                 if (exec->hadException())
       
   635                     return exec->exception();
       
   636             }
       
   637 
       
   638             if (!converted) {
       
   639                 if (actual.isVariant()) {
       
   640                     if (tid == -1)
       
   641                         tid = argType.typeId();
       
   642                     QVariant vv = actual.toVariant();
       
   643                     if (vv.canConvert(QVariant::Type(tid))) {
       
   644                         v = vv;
       
   645                         converted = v.convert(QVariant::Type(tid));
       
   646                         if (converted && (vv.userType() != tid))
       
   647                             matchDistance += 10;
       
   648                     } else {
       
   649                         QByteArray vvTypeName = vv.typeName();
       
   650                         if (vvTypeName.endsWith('*')
       
   651                             && (vvTypeName.left(vvTypeName.size()-1) == argType.name())) {
       
   652                             v = QVariant(tid, *reinterpret_cast<void* *>(vv.data()));
       
   653                             converted = true;
       
   654                             matchDistance += 10;
       
   655                         }
       
   656                     }
       
   657                 } else if (actual.isNumber() || actual.isString()) {
       
   658                     // see if it's an enum value
       
   659                     QMetaEnum m;
       
   660                     if (argType.isMetaEnum()) {
       
   661                         m = meta->enumerator(argType.enumeratorIndex());
       
   662                     } else {
       
   663                         int mi = indexOfMetaEnum(meta, argType.name());
       
   664                         if (mi != -1)
       
   665                             m = meta->enumerator(mi);
       
   666                     }
       
   667                     if (m.isValid()) {
       
   668                         if (actual.isNumber()) {
       
   669                             int ival = actual.toInt32();
       
   670                             if (m.valueToKey(ival) != 0) {
       
   671                                 qVariantSetValue(v, ival);
       
   672                                 converted = true;
       
   673                                 matchDistance += 10;
       
   674                             }
       
   675                         } else {
       
   676                             QString sval = actual.toString();
       
   677                             int ival = m.keyToValue(sval.toLatin1());
       
   678                             if (ival != -1) {
       
   679                                 qVariantSetValue(v, ival);
       
   680                                 converted = true;
       
   681                                 matchDistance += 10;
       
   682                             }
       
   683                         }
       
   684                     }
       
   685                 }
       
   686             } else {
       
   687                 // determine how well the conversion matched
       
   688                 if (actual.isNumber()) {
       
   689                     switch (tid) {
       
   690                     case QMetaType::Double:
       
   691                         // perfect
       
   692                         break;
       
   693                     case QMetaType::Float:
       
   694                         matchDistance += 1;
       
   695                         break;
       
   696                     case QMetaType::LongLong:
       
   697                     case QMetaType::ULongLong:
       
   698                         matchDistance += 2;
       
   699                         break;
       
   700                     case QMetaType::Long:
       
   701                     case QMetaType::ULong:
       
   702                         matchDistance += 3;
       
   703                         break;
       
   704                     case QMetaType::Int:
       
   705                     case QMetaType::UInt:
       
   706                         matchDistance += 4;
       
   707                         break;
       
   708                     case QMetaType::Short:
       
   709                     case QMetaType::UShort:
       
   710                         matchDistance += 5;
       
   711                         break;
       
   712                     case QMetaType::Char:
       
   713                     case QMetaType::UChar:
       
   714                         matchDistance += 6;
       
   715                         break;
       
   716                     default:
       
   717                         matchDistance += 10;
       
   718                         break;
       
   719                     }
       
   720                 } else if (actual.isString()) {
       
   721                     switch (tid) {
       
   722                     case QMetaType::QString:
       
   723                         // perfect
       
   724                         break;
       
   725                     default:
       
   726                         matchDistance += 10;
       
   727                         break;
       
   728                     }
       
   729                 } else if (actual.isBoolean()) {
       
   730                     switch (tid) {
       
   731                     case QMetaType::Bool:
       
   732                         // perfect
       
   733                         break;
       
   734                     default:
       
   735                         matchDistance += 10;
       
   736                         break;
       
   737                     }
       
   738                 } else if (actual.isDate()) {
       
   739                     switch (tid) {
       
   740                     case QMetaType::QDateTime:
       
   741                         // perfect
       
   742                         break;
       
   743                     case QMetaType::QDate:
       
   744                         matchDistance += 1;
       
   745                         break;
       
   746                     case QMetaType::QTime:
       
   747                         matchDistance += 2;
       
   748                         break;
       
   749                     default:
       
   750                         matchDistance += 10;
       
   751                         break;
       
   752                     }
       
   753                 } else if (actual.isRegExp()) {
       
   754                     switch (tid) {
       
   755                     case QMetaType::QRegExp:
       
   756                         // perfect
       
   757                         break;
       
   758                     default:
       
   759                         matchDistance += 10;
       
   760                         break;
       
   761                     }
       
   762                 } else if (actual.isVariant()) {
       
   763                     if (argType.isVariant()
       
   764                         || (actual.toVariant().userType() == tid)) {
       
   765                         // perfect
       
   766                     } else {
       
   767                         matchDistance += 10;
       
   768                     }
       
   769                 } else if (actual.isArray()) {
       
   770                     switch (tid) {
       
   771                     case QMetaType::QStringList:
       
   772                     case QMetaType::QVariantList:
       
   773                         matchDistance += 5;
       
   774                         break;
       
   775                     default:
       
   776                         matchDistance += 10;
       
   777                         break;
       
   778                     }
       
   779                 } else if (actual.isQObject()) {
       
   780                     switch (tid) {
       
   781                     case QMetaType::QObjectStar:
       
   782                     case QMetaType::QWidgetStar:
       
   783                         // perfect
       
   784                         break;
       
   785                     default:
       
   786                         matchDistance += 10;
       
   787                         break;
       
   788                     }
       
   789                 } else if (actual.isNull()) {
       
   790                     switch (tid) {
       
   791                     case QMetaType::VoidStar:
       
   792                     case QMetaType::QObjectStar:
       
   793                     case QMetaType::QWidgetStar:
       
   794                         // perfect
       
   795                         break;
       
   796                     default:
       
   797                         if (!argType.name().endsWith('*'))
       
   798                             matchDistance += 10;
       
   799                         break;
       
   800                     }
       
   801                 } else {
       
   802                     matchDistance += 10;
       
   803                 }
       
   804             }
       
   805 
       
   806             if (converted)
       
   807                 args[i+1] = v;
       
   808         }
       
   809 
       
   810         if (converted) {
       
   811             if ((scriptArgs.size() == (size_t)mtd.argumentCount())
       
   812                 && (matchDistance == 0)) {
       
   813                 // perfect match, use this one
       
   814                 chosenMethod = mtd;
       
   815                 chosenIndex = index;
       
   816                 break;
       
   817             } else {
       
   818                 bool redundant = false;
       
   819                 if ((callType != QMetaMethod::Constructor)
       
   820                     && (index < meta->methodOffset())) {
       
   821                     // it is possible that a virtual method is redeclared in a subclass,
       
   822                     // in which case we want to ignore the superclass declaration
       
   823                     for (int i = 0; i < candidates.size(); ++i) {
       
   824                         const QScriptMetaArguments &other = candidates.at(i);
       
   825                         if (mtd.types() == other.method.types()) {
       
   826                             redundant = true;
       
   827                             break;
       
   828                         }
       
   829                     }
       
   830                 }
       
   831                 if (!redundant) {
       
   832                     QScriptMetaArguments metaArgs(matchDistance, index, mtd, args);
       
   833                     if (candidates.isEmpty()) {
       
   834                         candidates.append(metaArgs);
       
   835                     } else {
       
   836                         const QScriptMetaArguments &otherArgs = candidates.at(0);
       
   837                         if ((args.count() > otherArgs.args.count())
       
   838                             || ((args.count() == otherArgs.args.count())
       
   839                                 && (matchDistance <= otherArgs.matchDistance))) {
       
   840                             candidates.prepend(metaArgs);
       
   841                         } else {
       
   842                             candidates.append(metaArgs);
       
   843                         }
       
   844                     }
       
   845                 }
       
   846             }
       
   847         } else if (mtd.fullyResolved()) {
       
   848             conversionFailed.append(index);
       
   849         }
       
   850 
       
   851         if (!maybeOverloaded)
       
   852             break;
       
   853     }
       
   854 
       
   855     JSC::JSValue result;
       
   856     if ((chosenIndex == -1) && candidates.isEmpty()) {
       
   857 //        context->calleeMetaIndex = initialIndex;
       
   858 //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
       
   859 //        engine->notifyFunctionEntry(context);
       
   860 //#endif
       
   861         if (!conversionFailed.isEmpty()) {
       
   862             QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
       
   863                               .arg(QLatin1String(funName));
       
   864             for (int i = 0; i < conversionFailed.size(); ++i) {
       
   865                 if (i > 0)
       
   866                     message += QLatin1String("\n");
       
   867                 QMetaMethod mtd = metaMethod(meta, callType, conversionFailed.at(i));
       
   868                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
       
   869             }
       
   870             result = JSC::throwError(exec, JSC::TypeError, message);
       
   871         } else if (!unresolved.isEmpty()) {
       
   872             QScriptMetaArguments argsInstance = unresolved.first();
       
   873             int unresolvedIndex = argsInstance.method.firstUnresolvedIndex();
       
   874             Q_ASSERT(unresolvedIndex != -1);
       
   875             QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex);
       
   876             QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name());
       
   877             QString message = QString::fromLatin1("cannot call %0(): ")
       
   878                               .arg(QString::fromLatin1(funName));
       
   879             if (unresolvedIndex > 0) {
       
   880                 message.append(QString::fromLatin1("argument %0 has unknown type `%1'").
       
   881                                arg(unresolvedIndex).arg(unresolvedTypeName));
       
   882             } else {
       
   883                 message.append(QString::fromLatin1("unknown return type `%0'")
       
   884                                .arg(unresolvedTypeName));
       
   885             }
       
   886             message.append(QString::fromLatin1(" (register the type with qScriptRegisterMetaType())"));
       
   887             result = JSC::throwError(exec, JSC::TypeError, message);
       
   888         } else {
       
   889             QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
       
   890                               .arg(QLatin1String(funName));
       
   891             for (int i = 0; i < tooFewArgs.size(); ++i) {
       
   892                 if (i > 0)
       
   893                     message += QLatin1String("\n");
       
   894                 QMetaMethod mtd = metaMethod(meta, callType, tooFewArgs.at(i));
       
   895                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
       
   896             }
       
   897             result = JSC::throwError(exec, JSC::SyntaxError, message);
       
   898         }
       
   899     } else {
       
   900         if (chosenIndex == -1) {
       
   901             QScriptMetaArguments metaArgs = candidates.at(0);
       
   902             if ((candidates.size() > 1)
       
   903                 && (metaArgs.args.count() == candidates.at(1).args.count())
       
   904                 && (metaArgs.matchDistance == candidates.at(1).matchDistance)) {
       
   905                 // ambiguous call
       
   906                 QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
       
   907                                   .arg(QLatin1String(funName));
       
   908                 for (int i = 0; i < candidates.size(); ++i) {
       
   909                     if (i > 0)
       
   910                         message += QLatin1String("\n");
       
   911                     QMetaMethod mtd = metaMethod(meta, callType, candidates.at(i).index);
       
   912                     message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
       
   913                 }
       
   914                 result = JSC::throwError(exec, JSC::TypeError, message);
       
   915             } else {
       
   916                 chosenMethod = metaArgs.method;
       
   917                 chosenIndex = metaArgs.index;
       
   918                 args = metaArgs.args;
       
   919             }
       
   920         }
       
   921 
       
   922         if (chosenIndex != -1) {
       
   923             // call it
       
   924 //            context->calleeMetaIndex = chosenIndex;
       
   925 
       
   926             QVarLengthArray<void*, 9> array(args.count());
       
   927             void **params = array.data();
       
   928             for (int i = 0; i < args.count(); ++i) {
       
   929                 const QVariant &v = args[i];
       
   930                 switch (chosenMethod.type(i).kind()) {
       
   931                 case QScriptMetaType::Variant:
       
   932                     params[i] = const_cast<QVariant*>(&v);
       
   933                     break;
       
   934                 case QScriptMetaType::MetaType:
       
   935                 case QScriptMetaType::MetaEnum:
       
   936                 case QScriptMetaType::Unresolved:
       
   937                     params[i] = const_cast<void*>(v.constData());
       
   938                     break;
       
   939                 default:
       
   940                     Q_ASSERT(0);
       
   941                 }
       
   942             }
       
   943 
       
   944             QScriptable *scriptable = 0;
       
   945             if (thisQObject)
       
   946                 scriptable = scriptableFromQObject(thisQObject);
       
   947             QScriptEngine *oldEngine = 0;
       
   948             if (scriptable) {
       
   949                 oldEngine = QScriptablePrivate::get(scriptable)->engine;
       
   950                 QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
       
   951             }
       
   952 
       
   953 // ### fixme
       
   954 //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
       
   955 //            engine->notifyFunctionEntry(context);
       
   956 //#endif
       
   957 
       
   958             if (callType == QMetaMethod::Constructor) {
       
   959                 Q_ASSERT(meta != 0);
       
   960                 meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
       
   961             } else {
       
   962                 QMetaObject::metacall(thisQObject, QMetaObject::InvokeMetaMethod, chosenIndex, params);
       
   963             }
       
   964 
       
   965             if (scriptable)
       
   966                 QScriptablePrivate::get(scriptable)->engine = oldEngine;
       
   967 
       
   968             if (exec->hadException()) {
       
   969                 result = exec->exception() ; // propagate
       
   970             } else {
       
   971                 QScriptMetaType retType = chosenMethod.returnType();
       
   972                 if (retType.isVariant()) {
       
   973                     result = engine->jscValueFromVariant(*(QVariant *)params[0]);
       
   974                 } else if (retType.typeId() != 0) {
       
   975                     result = engine->scriptValueToJSCValue(engine->create(retType.typeId(), params[0]));
       
   976                     if (!result) {
       
   977                         QScriptValue sv = QScriptEnginePrivate::get(engine)->newVariant(QVariant(retType.typeId(), params[0]));
       
   978                         result = engine->scriptValueToJSCValue(sv);
       
   979                     }
       
   980                 } else {
       
   981                     result = JSC::jsUndefined();
       
   982                 }
       
   983             }
       
   984         }
       
   985     }
       
   986 
       
   987     return result;
       
   988 }
       
   989 
       
   990 JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
       
   991                                  const JSC::ArgList &scriptArgs)
       
   992 {
       
   993     Q_ASSERT(data->object.inherits(&QScriptObject::info));
       
   994     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(data->object));
       
   995     QScriptObjectDelegate *delegate = scriptObject->delegate();
       
   996     Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
       
   997     QObject *qobj = static_cast<QScript::QObjectDelegate*>(delegate)->value();
       
   998     Q_ASSERT_X(qobj != 0, "QtFunction::call", "handle the case when QObject has been deleted");
       
   999     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
       
  1000 
       
  1001     const QMetaObject *meta = qobj->metaObject();
       
  1002     QObject *thisQObject = 0;
       
  1003     thisValue = engine->toUsableValue(thisValue);
       
  1004     if (thisValue.inherits(&QScriptObject::info)) {
       
  1005         delegate = static_cast<QScriptObject*>(JSC::asObject(thisValue))->delegate();
       
  1006         if (delegate && (delegate->type() == QScriptObjectDelegate::QtObject))
       
  1007             thisQObject = static_cast<QScript::QObjectDelegate*>(delegate)->value();
       
  1008     }
       
  1009     if (!thisQObject)
       
  1010         thisQObject = qobj; // ### TypeError
       
  1011 
       
  1012     if (!meta->cast(thisQObject)) {
       
  1013         // invoking a function in the prototype
       
  1014         thisQObject = qobj;
       
  1015     }
       
  1016 
       
  1017     return callQtMethod(exec, QMetaMethod::Method, thisQObject, scriptArgs,
       
  1018                         meta, data->initialIndex, data->maybeOverloaded);
       
  1019 }
       
  1020 
       
  1021 const JSC::ClassInfo QtFunction::info = { "QtFunction", &InternalFunction::info, 0, 0 };
       
  1022 
       
  1023 JSC::JSValue JSC_HOST_CALL QtFunction::call(JSC::ExecState *exec, JSC::JSObject *callee,
       
  1024                                             JSC::JSValue thisValue, const JSC::ArgList &args)
       
  1025 {
       
  1026     if (!callee->inherits(&QtFunction::info))
       
  1027         return throwError(exec, JSC::TypeError, "callee is not a QtFunction object");
       
  1028     QtFunction *qfun =  static_cast<QtFunction*>(callee);
       
  1029     QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
       
  1030     JSC::ExecState *previousFrame = eng_p->currentFrame;
       
  1031     eng_p->currentFrame = exec;
       
  1032     eng_p->pushContext(exec, thisValue, args, callee);
       
  1033     JSC::JSValue result = qfun->execute(eng_p->currentFrame, thisValue, args);
       
  1034     eng_p->popContext();
       
  1035     eng_p->currentFrame = previousFrame;
       
  1036     return result;
       
  1037 }
       
  1038 
       
  1039 const JSC::ClassInfo QtPropertyFunction::info = { "QtPropertyFunction", &InternalFunction::info, 0, 0 };
       
  1040 
       
  1041 QtPropertyFunction::QtPropertyFunction(const QMetaObject *meta, int index,
       
  1042                                        JSC::JSGlobalData *data,
       
  1043                                        WTF::PassRefPtr<JSC::Structure> sid,
       
  1044                                        const JSC::Identifier &ident)
       
  1045     : JSC::InternalFunction(data, sid, ident),
       
  1046       data(new Data(meta, index))
       
  1047 {
       
  1048 }
       
  1049 
       
  1050 QtPropertyFunction::~QtPropertyFunction()
       
  1051 {
       
  1052     delete data;
       
  1053 }
       
  1054 
       
  1055 JSC::CallType QtPropertyFunction::getCallData(JSC::CallData &callData)
       
  1056 {
       
  1057     callData.native.function = call;
       
  1058     return JSC::CallTypeHost;
       
  1059 }
       
  1060 
       
  1061 JSC::JSValue JSC_HOST_CALL QtPropertyFunction::call(
       
  1062     JSC::ExecState *exec, JSC::JSObject *callee,
       
  1063     JSC::JSValue thisValue, const JSC::ArgList &args)
       
  1064 {
       
  1065     if (!callee->inherits(&QtPropertyFunction::info))
       
  1066         return throwError(exec, JSC::TypeError, "callee is not a QtPropertyFunction object");
       
  1067     QtPropertyFunction *qfun =  static_cast<QtPropertyFunction*>(callee);
       
  1068     QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
       
  1069     JSC::ExecState *previousFrame = eng_p->currentFrame;
       
  1070     eng_p->currentFrame = exec;
       
  1071     eng_p->pushContext(exec, thisValue, args, callee);
       
  1072     JSC::JSValue result = qfun->execute(eng_p->currentFrame, thisValue, args);
       
  1073     eng_p->popContext();
       
  1074     eng_p->currentFrame = previousFrame;
       
  1075     return result;
       
  1076 }
       
  1077 
       
  1078 JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec,
       
  1079                                          JSC::JSValue thisValue,
       
  1080                                          const JSC::ArgList &args)
       
  1081 {
       
  1082     JSC::JSValue result = JSC::jsUndefined();
       
  1083 
       
  1084     // ### don't go via QScriptValue
       
  1085     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
       
  1086     thisValue = engine->toUsableValue(thisValue);
       
  1087     QScriptValue object = engine->scriptValueFromJSCValue(thisValue);
       
  1088     QObject *qobject = object.toQObject();
       
  1089     while ((!qobject || (qobject->metaObject() != data->meta))
       
  1090            && object.prototype().isObject()) {
       
  1091         object = object.prototype();
       
  1092         qobject = object.toQObject();
       
  1093     }
       
  1094     Q_ASSERT_X(qobject, Q_FUNC_INFO, "this-object must be a QObject");
       
  1095 
       
  1096     QMetaProperty prop = data->meta->property(data->index);
       
  1097     Q_ASSERT(prop.isScriptable());
       
  1098     if (args.size() == 0) {
       
  1099         // get
       
  1100         if (prop.isValid()) {
       
  1101             QScriptable *scriptable = scriptableFromQObject(qobject);
       
  1102             QScriptEngine *oldEngine = 0;
       
  1103             if (scriptable) {
       
  1104                 oldEngine = QScriptablePrivate::get(scriptable)->engine;
       
  1105                 QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
       
  1106             }
       
  1107 
       
  1108             QVariant v = prop.read(qobject);
       
  1109 
       
  1110             if (scriptable)
       
  1111                 QScriptablePrivate::get(scriptable)->engine = oldEngine;
       
  1112 
       
  1113             result = engine->jscValueFromVariant(v);
       
  1114         }
       
  1115     } else {
       
  1116         // set
       
  1117         JSC::JSValue arg = args.at(0);
       
  1118         QVariant v;
       
  1119         if (prop.isEnumType() && arg.isString()
       
  1120             && !engine->hasDemarshalFunction(prop.userType())) {
       
  1121             // give QMetaProperty::write() a chance to convert from
       
  1122             // string to enum value
       
  1123             v = (QString)arg.toString(exec);
       
  1124         } else {
       
  1125             // ### don't go via QScriptValue
       
  1126             QScriptValue tmp = engine->scriptValueFromJSCValue(arg);
       
  1127             v = variantFromValue(engine, prop.userType(), tmp);
       
  1128         }
       
  1129 
       
  1130         QScriptable *scriptable = scriptableFromQObject(qobject);
       
  1131         QScriptEngine *oldEngine = 0;
       
  1132         if (scriptable) {
       
  1133             oldEngine = QScriptablePrivate::get(scriptable)->engine;
       
  1134             QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
       
  1135         }
       
  1136 
       
  1137         prop.write(qobject, v);
       
  1138 
       
  1139         if (scriptable)
       
  1140             QScriptablePrivate::get(scriptable)->engine = oldEngine;
       
  1141 
       
  1142         result = arg;
       
  1143     }
       
  1144     return result;
       
  1145 }
       
  1146 
       
  1147 const QMetaObject *QtPropertyFunction::metaObject() const
       
  1148 {
       
  1149     return data->meta;
       
  1150 }
       
  1151 
       
  1152 int QtPropertyFunction::propertyIndex() const
       
  1153 {
       
  1154     return data->index;
       
  1155 }
       
  1156 
       
  1157 
       
  1158 QObjectDelegate::QObjectDelegate(
       
  1159     QObject *object, QScriptEngine::ValueOwnership ownership,
       
  1160     const QScriptEngine::QObjectWrapOptions &options)
       
  1161     : data(new Data(object, ownership, options))
       
  1162 {
       
  1163 }
       
  1164 
       
  1165 QObjectDelegate::~QObjectDelegate()
       
  1166 {
       
  1167     switch (data->ownership) {
       
  1168     case QScriptEngine::QtOwnership:
       
  1169         break;
       
  1170     case QScriptEngine::ScriptOwnership:
       
  1171         if (data->value)
       
  1172             delete data->value; // ### fixme
       
  1173 //            eng->disposeQObject(value);
       
  1174         break;
       
  1175     case QScriptEngine::AutoOwnership:
       
  1176         if (data->value && !data->value->parent())
       
  1177             delete data->value; // ### fixme
       
  1178 //            eng->disposeQObject(value);
       
  1179         break;
       
  1180     }
       
  1181     delete data;
       
  1182 }
       
  1183 
       
  1184 QScriptObjectDelegate::Type QObjectDelegate::type() const
       
  1185 {
       
  1186     return QtObject;
       
  1187 }
       
  1188 
       
  1189 bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState *exec,
       
  1190                                          const JSC::Identifier &propertyName,
       
  1191                                          JSC::PropertySlot &slot)
       
  1192 {
       
  1193     QByteArray name = QString(propertyName.ustring()).toLatin1();
       
  1194     QObject *qobject = data->value;
       
  1195     if (!qobject) {
       
  1196         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
       
  1197                           .arg(QString::fromLatin1(name));
       
  1198         slot.setValue(JSC::throwError(exec, JSC::GeneralError, message));
       
  1199         return true;
       
  1200     }
       
  1201 
       
  1202     const QMetaObject *meta = qobject->metaObject();
       
  1203     {
       
  1204         QHash<QByteArray, JSC::JSValue>::const_iterator it = data->cachedMembers.constFind(name);
       
  1205         if (it != data->cachedMembers.constEnd()) {
       
  1206             if (GeneratePropertyFunctions && (meta->indexOfProperty(name) != -1))
       
  1207                 slot.setGetterSlot(JSC::asObject(it.value()));
       
  1208             else
       
  1209                 slot.setValue(it.value());
       
  1210             return true;
       
  1211         }
       
  1212     }
       
  1213 
       
  1214     const QScriptEngine::QObjectWrapOptions &opt = data->options;
       
  1215     QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
       
  1216     int index = -1;
       
  1217     if (name.contains('(')) {
       
  1218         QByteArray normalized = QMetaObject::normalizedSignature(name);
       
  1219         if (-1 != (index = meta->indexOfMethod(normalized))) {
       
  1220             QMetaMethod method = meta->method(index);
       
  1221             if (hasMethodAccess(method, index, opt)) {
       
  1222                 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1223                     || (index >= meta->methodOffset())) {
       
  1224                     QtFunction *fun = new (exec)QtFunction(
       
  1225                         object, index, /*maybeOverloaded=*/false,
       
  1226                         &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
       
  1227                         propertyName);
       
  1228                     slot.setValue(fun);
       
  1229                     data->cachedMembers.insert(name, fun);
       
  1230                     return true;
       
  1231                 }
       
  1232             }
       
  1233         }
       
  1234     }
       
  1235 
       
  1236     index = meta->indexOfProperty(name);
       
  1237     if (index != -1) {
       
  1238         QMetaProperty prop = meta->property(index);
       
  1239         if (prop.isScriptable()) {
       
  1240             if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
       
  1241                 || (index >= meta->propertyOffset())) {
       
  1242                 if (GeneratePropertyFunctions) {
       
  1243                     QtPropertyFunction *fun = new (exec)QtPropertyFunction(
       
  1244                         meta, index, &exec->globalData(),
       
  1245                         eng->originalGlobalObject()->functionStructure(),
       
  1246                         propertyName);
       
  1247                     data->cachedMembers.insert(name, fun);
       
  1248                     slot.setGetterSlot(fun);
       
  1249                 } else {
       
  1250                     JSC::JSValue val;
       
  1251                     if (!prop.isValid())
       
  1252                         val = JSC::jsUndefined();
       
  1253                     else
       
  1254                         val = eng->jscValueFromVariant(prop.read(qobject));
       
  1255                     slot.setValue(val);
       
  1256                 }
       
  1257                 return true;
       
  1258             }
       
  1259         }
       
  1260     }
       
  1261 
       
  1262     index = qobject->dynamicPropertyNames().indexOf(name);
       
  1263     if (index != -1) {
       
  1264         JSC::JSValue val = eng->jscValueFromVariant(qobject->property(name));
       
  1265         slot.setValue(val);
       
  1266         return true;
       
  1267     }
       
  1268 
       
  1269     const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1270                        ? meta->methodOffset() : 0;
       
  1271     for (index = meta->methodCount() - 1; index >= offset; --index) {
       
  1272         QMetaMethod method = meta->method(index);
       
  1273         if (hasMethodAccess(method, index, opt)
       
  1274             && (methodName(method) == name)) {
       
  1275             QtFunction *fun = new (exec)QtFunction(
       
  1276                 object, index, /*maybeOverloaded=*/true,
       
  1277                 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
       
  1278                 propertyName);
       
  1279             slot.setValue(fun);
       
  1280             data->cachedMembers.insert(name, fun);
       
  1281             return true;
       
  1282         }
       
  1283     }
       
  1284 
       
  1285     if (!(opt & QScriptEngine::ExcludeChildObjects)) {
       
  1286         QList<QObject*> children = qobject->children();
       
  1287         for (index = 0; index < children.count(); ++index) {
       
  1288             QObject *child = children.at(index);
       
  1289             if (child->objectName() == QString(propertyName.ustring())) {
       
  1290                 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
       
  1291                 QScriptValue tmp = QScriptEnginePrivate::get(eng)->newQObject(child, QScriptEngine::QtOwnership, opt);
       
  1292                 slot.setValue(eng->scriptValueToJSCValue(tmp));
       
  1293                 return true;
       
  1294             }
       
  1295         }
       
  1296     }
       
  1297 
       
  1298     return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot);
       
  1299 }
       
  1300 
       
  1301 void QObjectDelegate::put(QScriptObject *object, JSC::ExecState* exec,
       
  1302                           const JSC::Identifier& propertyName,
       
  1303                           JSC::JSValue value, JSC::PutPropertySlot &slot)
       
  1304 {
       
  1305     QByteArray name = ((QString)propertyName.ustring()).toLatin1();
       
  1306     QObject *qobject = data->value;
       
  1307     if (!qobject) {
       
  1308         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
       
  1309                           .arg(QString::fromLatin1(name));
       
  1310         JSC::throwError(exec, JSC::GeneralError, message);
       
  1311         return;
       
  1312     }
       
  1313 
       
  1314     const QScriptEngine::QObjectWrapOptions &opt = data->options;
       
  1315     const QMetaObject *meta = qobject->metaObject();
       
  1316     QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
       
  1317     int index = -1;
       
  1318     if (name.contains('(')) {
       
  1319         QByteArray normalized = QMetaObject::normalizedSignature(name);
       
  1320         if (-1 != (index = meta->indexOfMethod(normalized))) {
       
  1321             QMetaMethod method = meta->method(index);
       
  1322             if (hasMethodAccess(method, index, opt)) {
       
  1323                 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1324                     || (index >= meta->methodOffset())) {
       
  1325                     data->cachedMembers.insert(name, value);
       
  1326                     return;
       
  1327                 }
       
  1328             }
       
  1329         }
       
  1330     }
       
  1331 
       
  1332     index = meta->indexOfProperty(name);
       
  1333     if (index != -1) {
       
  1334         QMetaProperty prop = meta->property(index);
       
  1335         if (prop.isScriptable()) {
       
  1336             if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
       
  1337                 || (index >= meta->propertyOffset())) {
       
  1338                 if (GeneratePropertyFunctions) {
       
  1339                     // ### ideally JSC would do this for us already, i.e. find out
       
  1340                     // that the property is a setter and call the setter.
       
  1341                     // Maybe QtPropertyFunction needs to inherit JSC::GetterSetter.
       
  1342                     JSC::JSValue fun;
       
  1343                     QHash<QByteArray, JSC::JSValue>::const_iterator it;
       
  1344                     it = data->cachedMembers.constFind(name);
       
  1345                     if (it != data->cachedMembers.constEnd()) {
       
  1346                         fun = it.value();
       
  1347                     } else {
       
  1348                         fun = new (exec)QtPropertyFunction(
       
  1349                             meta, index, &exec->globalData(),
       
  1350                             eng->originalGlobalObject()->functionStructure(),
       
  1351                             propertyName);
       
  1352                         data->cachedMembers.insert(name, fun);
       
  1353                     }
       
  1354                     JSC::CallData callData;
       
  1355                     JSC::CallType callType = fun.getCallData(callData);
       
  1356                     JSC::JSValue argv[1] = { value };
       
  1357                     JSC::ArgList args(argv, 1);
       
  1358                     (void)JSC::call(exec, fun, callType, callData, object, args);
       
  1359                 } else {
       
  1360                     QVariant v;
       
  1361                     if (prop.isEnumType() && value.isString()
       
  1362                         && !eng->hasDemarshalFunction(prop.userType())) {
       
  1363                         // give QMetaProperty::write() a chance to convert from
       
  1364                         // string to enum value
       
  1365                         v = (QString)value.toString(exec);
       
  1366                     } else {
       
  1367                         v = eng->jscValueToVariant(value, prop.userType());
       
  1368                     }
       
  1369                     (void)prop.write(qobject, v);
       
  1370                 }
       
  1371                 return;
       
  1372             }
       
  1373         }
       
  1374     }
       
  1375 
       
  1376     const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1377                        ? meta->methodOffset() : 0;
       
  1378     for (index = meta->methodCount() - 1; index >= offset; --index) {
       
  1379         QMetaMethod method = meta->method(index);
       
  1380         if (hasMethodAccess(method, index, opt)
       
  1381             && (methodName(method) == name)) {
       
  1382             data->cachedMembers.insert(name, value);
       
  1383             return;
       
  1384         }
       
  1385     }
       
  1386 
       
  1387     index = qobject->dynamicPropertyNames().indexOf(name);
       
  1388     if ((index != -1) || (opt & QScriptEngine::AutoCreateDynamicProperties)) {
       
  1389         QVariant v = eng->scriptValueFromJSCValue(value).toVariant();
       
  1390         (void)qobject->setProperty(name, v);
       
  1391         return;
       
  1392     }
       
  1393 
       
  1394     QScriptObjectDelegate::put(object, exec, propertyName, value, slot);
       
  1395 }
       
  1396 
       
  1397 bool QObjectDelegate::deleteProperty(QScriptObject *object, JSC::ExecState *exec,
       
  1398                                      const JSC::Identifier& propertyName,
       
  1399                                      bool checkDontDelete)
       
  1400 {
       
  1401     QByteArray name = ((QString)propertyName.ustring()).toLatin1();
       
  1402     QObject *qobject = data->value;
       
  1403     if (!qobject) {
       
  1404         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
       
  1405                           .arg(QString::fromLatin1(name));
       
  1406         JSC::throwError(exec, JSC::GeneralError, message);
       
  1407         return false;
       
  1408     }
       
  1409 
       
  1410     const QMetaObject *meta = qobject->metaObject();
       
  1411     {
       
  1412         QHash<QByteArray, JSC::JSValue>::iterator it = data->cachedMembers.find(name);
       
  1413         if (it != data->cachedMembers.end()) {
       
  1414             if (GeneratePropertyFunctions && (meta->indexOfProperty(name) != -1))
       
  1415                 return false;
       
  1416             data->cachedMembers.erase(it);
       
  1417             return true;
       
  1418         }
       
  1419     }
       
  1420 
       
  1421     const QScriptEngine::QObjectWrapOptions &opt = data->options;
       
  1422     int index = meta->indexOfProperty(name);
       
  1423     if (index != -1) {
       
  1424         QMetaProperty prop = meta->property(index);
       
  1425         if (prop.isScriptable() &&
       
  1426             (!(opt & QScriptEngine::ExcludeSuperClassProperties)
       
  1427              || (index >= meta->propertyOffset()))) {
       
  1428                 return false;
       
  1429         }
       
  1430     }
       
  1431 
       
  1432     index = qobject->dynamicPropertyNames().indexOf(name);
       
  1433     if (index != -1) {
       
  1434         (void)qobject->setProperty(name, QVariant());
       
  1435         return true;
       
  1436     }
       
  1437 
       
  1438     return QScriptObjectDelegate::deleteProperty(object, exec, propertyName, checkDontDelete);
       
  1439 }
       
  1440 
       
  1441 bool QObjectDelegate::getPropertyAttributes(const QScriptObject *object,
       
  1442                                             JSC::ExecState *exec,
       
  1443                                             const JSC::Identifier &propertyName,
       
  1444                                             unsigned &attributes) const
       
  1445 {
       
  1446     // ### try to avoid duplicating logic from getOwnPropertySlot()
       
  1447     QByteArray name = ((QString)propertyName.ustring()).toLatin1();
       
  1448     QObject *qobject = data->value;
       
  1449     if (!qobject)
       
  1450         return false;
       
  1451 
       
  1452     const QScriptEngine::QObjectWrapOptions &opt = data->options;
       
  1453     const QMetaObject *meta = qobject->metaObject();
       
  1454     int index = -1;
       
  1455     if (name.contains('(')) {
       
  1456         QByteArray normalized = QMetaObject::normalizedSignature(name);
       
  1457         if (-1 != (index = meta->indexOfMethod(normalized))) {
       
  1458             QMetaMethod method = meta->method(index);
       
  1459             if (hasMethodAccess(method, index, opt)) {
       
  1460                 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1461                     || (index >= meta->methodOffset())) {
       
  1462                     attributes = QObjectMemberAttribute;
       
  1463                     if (opt & QScriptEngine::SkipMethodsInEnumeration)
       
  1464                         attributes |= JSC::DontEnum;
       
  1465                     return true;
       
  1466                 }
       
  1467             }
       
  1468         }
       
  1469     }
       
  1470 
       
  1471     index = meta->indexOfProperty(name);
       
  1472     if (index != -1) {
       
  1473         QMetaProperty prop = meta->property(index);
       
  1474         if (prop.isScriptable()) {
       
  1475             if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
       
  1476                 || (index >= meta->propertyOffset())) {
       
  1477                 attributes = flagsForMetaProperty(prop);
       
  1478                 return true;
       
  1479             }
       
  1480         }
       
  1481     }
       
  1482 
       
  1483     index = qobject->dynamicPropertyNames().indexOf(name);
       
  1484     if (index != -1) {
       
  1485         attributes = QObjectMemberAttribute;
       
  1486         return true;
       
  1487     }
       
  1488 
       
  1489     const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1490                        ? meta->methodOffset() : 0;
       
  1491     for (index = meta->methodCount() - 1; index >= offset; --index) {
       
  1492         QMetaMethod method = meta->method(index);
       
  1493         if (hasMethodAccess(method, index, opt)
       
  1494             && (methodName(method) == name)) {
       
  1495             attributes = QObjectMemberAttribute;
       
  1496             if (opt & QScriptEngine::SkipMethodsInEnumeration)
       
  1497                 attributes |= JSC::DontEnum;
       
  1498             return true;
       
  1499         }
       
  1500     }
       
  1501 
       
  1502     if (!(opt & QScriptEngine::ExcludeChildObjects)) {
       
  1503         QList<QObject*> children = qobject->children();
       
  1504         for (index = 0; index < children.count(); ++index) {
       
  1505             QObject *child = children.at(index);
       
  1506             if (child->objectName() == (QString)(propertyName.ustring())) {
       
  1507                 attributes = JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum;
       
  1508                 return true;
       
  1509             }
       
  1510         }
       
  1511     }
       
  1512 
       
  1513     return QScriptObjectDelegate::getPropertyAttributes(object, exec, propertyName, attributes);
       
  1514 }
       
  1515 
       
  1516 void QObjectDelegate::getOwnPropertyNames(QScriptObject *object, JSC::ExecState *exec,
       
  1517                                           JSC::PropertyNameArray &propertyNames,
       
  1518                                           bool includeNonEnumerable)
       
  1519 {
       
  1520     QObject *qobject = data->value;
       
  1521     if (!qobject) {
       
  1522         QString message = QString::fromLatin1("cannot get property names of deleted QObject");
       
  1523         JSC::throwError(exec, JSC::GeneralError, message);
       
  1524         return;
       
  1525     }
       
  1526 
       
  1527     const QScriptEngine::QObjectWrapOptions &opt = data->options;
       
  1528     const QMetaObject *meta = qobject->metaObject();
       
  1529     {
       
  1530         int i = (opt & QScriptEngine::ExcludeSuperClassProperties)
       
  1531                     ? meta->propertyOffset() : 0;
       
  1532         for ( ; i < meta->propertyCount(); ++i) {
       
  1533             QMetaProperty prop = meta->property(i);
       
  1534             if (isEnumerableMetaProperty(prop, meta, i)) {
       
  1535                 QString name = QString::fromLatin1(prop.name());
       
  1536                 propertyNames.add(JSC::Identifier(exec, name));
       
  1537             }
       
  1538         }
       
  1539     }
       
  1540 
       
  1541     {
       
  1542         QList<QByteArray> dpNames = qobject->dynamicPropertyNames();
       
  1543         for (int i = 0; i < dpNames.size(); ++i) {
       
  1544             QString name = QString::fromLatin1(dpNames.at(i));
       
  1545             propertyNames.add(JSC::Identifier(exec, name));
       
  1546         }
       
  1547     }
       
  1548 
       
  1549     if (!(opt & QScriptEngine::SkipMethodsInEnumeration)) {
       
  1550         int i = (opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1551                     ? meta->methodOffset() : 0;
       
  1552         for ( ; i < meta->methodCount(); ++i) {
       
  1553             QMetaMethod method = meta->method(i);
       
  1554             if (hasMethodAccess(method, i, opt)) {
       
  1555                 QMetaMethod method = meta->method(i);
       
  1556                 QString sig = QString::fromLatin1(method.signature());
       
  1557                 propertyNames.add(JSC::Identifier(exec, sig));
       
  1558             }
       
  1559         }
       
  1560     }
       
  1561 
       
  1562     QScriptObjectDelegate::getOwnPropertyNames(object, exec, propertyNames, includeNonEnumerable);
       
  1563 }
       
  1564 
       
  1565 void QObjectDelegate::markChildren(QScriptObject *object, JSC::MarkStack& markStack)
       
  1566 {
       
  1567     QHash<QByteArray, JSC::JSValue>::const_iterator it;
       
  1568     for (it = data->cachedMembers.constBegin(); it != data->cachedMembers.constEnd(); ++it) {
       
  1569         JSC::JSValue val = it.value();
       
  1570         if (val)
       
  1571             markStack.append(val);
       
  1572     }
       
  1573 
       
  1574     QScriptObjectDelegate::markChildren(object, markStack);
       
  1575 }
       
  1576 
       
  1577 bool QObjectDelegate::compareToObject(QScriptObject *, JSC::ExecState *exec, JSC::JSObject *o2)
       
  1578 {
       
  1579     if (!o2->inherits(&QScriptObject::info))
       
  1580         return false;
       
  1581     QScriptObject *object = static_cast<QScriptObject*>(o2);
       
  1582     QScriptObjectDelegate *delegate = object->delegate();
       
  1583     if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
       
  1584         return false;
       
  1585     return value() == static_cast<QObjectDelegate *>(delegate)->value();
       
  1586 }
       
  1587 
       
  1588 static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec, JSC::JSObject*,
       
  1589                                                             JSC::JSValue thisValue, const JSC::ArgList &args)
       
  1590 {
       
  1591     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
       
  1592     thisValue = engine->toUsableValue(thisValue);
       
  1593     if (!thisValue.inherits(&QScriptObject::info))
       
  1594         return throwError(exec, JSC::TypeError, "this object is not a QObject");
       
  1595     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue));
       
  1596     QScriptObjectDelegate *delegate = scriptObject->delegate();
       
  1597     if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
       
  1598         return throwError(exec, JSC::TypeError, "this object is not a QObject");
       
  1599     QObject *obj = static_cast<QObjectDelegate*>(delegate)->value();
       
  1600     QString name;
       
  1601     if (args.size() != 0)
       
  1602         name = args.at(0).toString(exec);
       
  1603     QObject *child = qFindChild<QObject*>(obj, name);
       
  1604     QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
       
  1605     return engine->newQObject(child, QScriptEngine::QtOwnership, opt);
       
  1606 }
       
  1607 
       
  1608 static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *exec, JSC::JSObject*,
       
  1609                                                                JSC::JSValue thisValue, const JSC::ArgList &args)
       
  1610 {
       
  1611     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
       
  1612     thisValue = engine->toUsableValue(thisValue);
       
  1613     // extract the QObject
       
  1614     if (!thisValue.inherits(&QScriptObject::info))
       
  1615         return throwError(exec, JSC::TypeError, "this object is not a QObject");
       
  1616     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue));
       
  1617     QScriptObjectDelegate *delegate = scriptObject->delegate();
       
  1618     if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
       
  1619         return throwError(exec, JSC::TypeError, "this object is not a QObject");
       
  1620     const QObject *const obj = static_cast<QObjectDelegate*>(delegate)->value();
       
  1621 
       
  1622     // find the children
       
  1623     QList<QObject *> children;
       
  1624     if (args.size() != 0) {
       
  1625         const JSC::JSValue arg = args.at(0);
       
  1626         if (arg.inherits(&JSC::RegExpObject::info)) {
       
  1627             const QObjectList allChildren= obj->children();
       
  1628 
       
  1629             JSC::RegExpObject *const regexp = JSC::asRegExpObject(arg);
       
  1630 
       
  1631             const int allChildrenCount = allChildren.size();
       
  1632             for (int i = 0; i < allChildrenCount; ++i) {
       
  1633                 QObject *const child = allChildren.at(i);
       
  1634                 const JSC::UString childName = child->objectName();
       
  1635                 JSC::RegExpConstructor* regExpConstructor = engine->originalGlobalObject()->regExpConstructor();
       
  1636                 int position;
       
  1637                 int length;
       
  1638                 regExpConstructor->performMatch(regexp->regExp(), childName, 0, position, length);
       
  1639                 if (position >= 0)
       
  1640                     children.append(child);
       
  1641             }
       
  1642         } else {
       
  1643             const QString name(args.at(0).toString(exec));
       
  1644             children = qFindChildren<QObject*>(obj, name);
       
  1645         }
       
  1646     } else {
       
  1647         children = qFindChildren<QObject*>(obj, QString());
       
  1648     }
       
  1649     // create the result array with the children
       
  1650     const int length = children.size();
       
  1651     JSC::JSArray *const result = JSC::constructEmptyArray(exec, length);
       
  1652 
       
  1653     QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
       
  1654     for (int i = 0; i < length; ++i) {
       
  1655         QObject *const child = children.at(i);
       
  1656         result->put(exec, i, engine->newQObject(child, QScriptEngine::QtOwnership, opt));
       
  1657     }
       
  1658     return JSC::JSValue(result);
       
  1659 }
       
  1660 
       
  1661 static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncToString(JSC::ExecState *exec, JSC::JSObject*,
       
  1662                                                            JSC::JSValue thisValue, const JSC::ArgList&)
       
  1663 {
       
  1664     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
       
  1665     thisValue = engine->toUsableValue(thisValue);
       
  1666     if (!thisValue.inherits(&QScriptObject::info))
       
  1667         return JSC::jsUndefined();
       
  1668     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue));
       
  1669     QScriptObjectDelegate *delegate = scriptObject->delegate();
       
  1670     if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
       
  1671         return JSC::jsUndefined();
       
  1672     QObject *obj = static_cast<QObjectDelegate*>(delegate)->value();
       
  1673     const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
       
  1674     QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed");
       
  1675     QString str = QString::fromUtf8("%0(name = \"%1\")")
       
  1676                   .arg(QLatin1String(meta->className())).arg(name);
       
  1677     return JSC::jsString(exec, str);
       
  1678 }
       
  1679 
       
  1680 QObjectPrototype::QObjectPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::Structure> structure,
       
  1681                                    JSC::Structure* prototypeFunctionStructure)
       
  1682     : QScriptObject(structure)
       
  1683 {
       
  1684     setDelegate(new QObjectDelegate(new QObjectPrototypeObject(), QScriptEngine::AutoOwnership,
       
  1685                                     QScriptEngine::ExcludeSuperClassMethods
       
  1686                                     | QScriptEngine::ExcludeSuperClassProperties
       
  1687                                     | QScriptEngine::ExcludeChildObjects));
       
  1688 
       
  1689     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
       
  1690     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum);
       
  1691     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum);
       
  1692 }
       
  1693 
       
  1694 const JSC::ClassInfo QMetaObjectWrapperObject::info = { "QMetaObject", 0, 0, 0 };
       
  1695 
       
  1696 QMetaObjectWrapperObject::QMetaObjectWrapperObject(
       
  1697     JSC::ExecState *exec, const QMetaObject *metaObject, JSC::JSValue ctor,
       
  1698     WTF::PassRefPtr<JSC::Structure> sid)
       
  1699     : JSC::JSObject(sid),
       
  1700       data(new Data(metaObject, ctor))
       
  1701 {
       
  1702     if (!ctor)
       
  1703         data->prototype = new (exec)JSC::JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
       
  1704 }
       
  1705 
       
  1706 QMetaObjectWrapperObject::~QMetaObjectWrapperObject()
       
  1707 {
       
  1708     delete data;
       
  1709 }
       
  1710 
       
  1711 bool QMetaObjectWrapperObject::getOwnPropertySlot(
       
  1712     JSC::ExecState *exec, const JSC::Identifier& propertyName,
       
  1713     JSC::PropertySlot &slot)
       
  1714 {
       
  1715     const QMetaObject *meta = data->value;
       
  1716     if (!meta)
       
  1717         return false;
       
  1718 
       
  1719     if (propertyName == exec->propertyNames().prototype) {
       
  1720         if (data->ctor)
       
  1721             slot.setValue(data->ctor.get(exec, propertyName));
       
  1722         else
       
  1723             slot.setValue(data->prototype);
       
  1724         return true;
       
  1725     }
       
  1726 
       
  1727     QByteArray name = QString(propertyName.ustring()).toLatin1();
       
  1728 
       
  1729     for (int i = 0; i < meta->enumeratorCount(); ++i) {
       
  1730         QMetaEnum e = meta->enumerator(i);
       
  1731         for (int j = 0; j < e.keyCount(); ++j) {
       
  1732             const char *key = e.key(j);
       
  1733             if (!qstrcmp(key, name.constData())) {
       
  1734                 slot.setValue(JSC::JSValue(exec, e.value(j)));
       
  1735                 return true;
       
  1736             }
       
  1737         }
       
  1738     }
       
  1739 
       
  1740     return JSC::JSObject::getOwnPropertySlot(exec, propertyName, slot);
       
  1741 }
       
  1742 
       
  1743 void QMetaObjectWrapperObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName,
       
  1744                                    JSC::JSValue value, JSC::PutPropertySlot &slot)
       
  1745 {
       
  1746     if (propertyName == exec->propertyNames().prototype) {
       
  1747         if (data->ctor)
       
  1748             data->ctor.put(exec, propertyName, value, slot);
       
  1749         else
       
  1750             data->prototype = value;
       
  1751         return;
       
  1752     }
       
  1753     const QMetaObject *meta = data->value;
       
  1754     if (meta) {
       
  1755         QByteArray name = QString(propertyName.ustring()).toLatin1();
       
  1756         for (int i = 0; i < meta->enumeratorCount(); ++i) {
       
  1757             QMetaEnum e = meta->enumerator(i);
       
  1758             for (int j = 0; j < e.keyCount(); ++j) {
       
  1759                 if (!qstrcmp(e.key(j), name.constData()))
       
  1760                     return;
       
  1761             }
       
  1762         }
       
  1763     }
       
  1764     JSC::JSObject::put(exec, propertyName, value, slot);
       
  1765 }
       
  1766 
       
  1767 bool QMetaObjectWrapperObject::deleteProperty(
       
  1768     JSC::ExecState *exec, const JSC::Identifier& propertyName,
       
  1769     bool checkDontDelete)
       
  1770 {
       
  1771     if (propertyName == exec->propertyNames().prototype)
       
  1772         return false;
       
  1773     const QMetaObject *meta = data->value;
       
  1774     if (meta) {
       
  1775         QByteArray name = QString(propertyName.ustring()).toLatin1();
       
  1776         for (int i = 0; i < meta->enumeratorCount(); ++i) {
       
  1777             QMetaEnum e = meta->enumerator(i);
       
  1778             for (int j = 0; j < e.keyCount(); ++j) {
       
  1779                 if (!qstrcmp(e.key(j), name.constData()))
       
  1780                     return false;
       
  1781             }
       
  1782         }
       
  1783     }
       
  1784     return JSC::JSObject::deleteProperty(exec, propertyName, checkDontDelete);
       
  1785 }
       
  1786 
       
  1787 bool QMetaObjectWrapperObject::getPropertyAttributes(JSC::ExecState *exec,
       
  1788                                                      const JSC::Identifier &propertyName,
       
  1789                                                      unsigned &attributes) const
       
  1790 {
       
  1791     if (propertyName == exec->propertyNames().prototype) {
       
  1792         attributes = JSC::DontDelete;
       
  1793         return true;
       
  1794     }
       
  1795     const QMetaObject *meta = data->value;
       
  1796     if (meta) {
       
  1797         QByteArray name = QString(propertyName.ustring()).toLatin1();
       
  1798         for (int i = 0; i < meta->enumeratorCount(); ++i) {
       
  1799             QMetaEnum e = meta->enumerator(i);
       
  1800             for (int j = 0; j < e.keyCount(); ++j) {
       
  1801                 if (!qstrcmp(e.key(j), name.constData())) {
       
  1802                     attributes = JSC::ReadOnly | JSC::DontDelete;
       
  1803                     return true;
       
  1804                 }
       
  1805             }
       
  1806         }
       
  1807     }
       
  1808     return JSC::JSObject::getPropertyAttributes(exec, propertyName, attributes);
       
  1809 }
       
  1810 
       
  1811 void QMetaObjectWrapperObject::getOwnPropertyNames(JSC::ExecState *exec,
       
  1812                                                    JSC::PropertyNameArray &propertyNames,
       
  1813                                                    bool includeNonEnumerable)
       
  1814 {
       
  1815     const QMetaObject *meta = data->value;
       
  1816     if (!meta)
       
  1817         return;
       
  1818     for (int i = 0; i < meta->enumeratorCount(); ++i) {
       
  1819         QMetaEnum e = meta->enumerator(i);
       
  1820         for (int j = 0; j < e.keyCount(); ++j)
       
  1821             propertyNames.add(JSC::Identifier(exec, e.key(j)));
       
  1822     }
       
  1823     JSC::JSObject::getOwnPropertyNames(exec, propertyNames, includeNonEnumerable);
       
  1824 }
       
  1825 
       
  1826 void QMetaObjectWrapperObject::markChildren(JSC::MarkStack& markStack)
       
  1827 {
       
  1828     if (data->ctor)
       
  1829         markStack.append(data->ctor);
       
  1830     if (data->prototype)
       
  1831         markStack.append(data->prototype);
       
  1832     JSC::JSObject::markChildren(markStack);
       
  1833 }
       
  1834 
       
  1835 JSC::CallType QMetaObjectWrapperObject::getCallData(JSC::CallData& callData)
       
  1836 {
       
  1837     callData.native.function = call;
       
  1838     return JSC::CallTypeHost;
       
  1839 }
       
  1840 
       
  1841 JSC::ConstructType QMetaObjectWrapperObject::getConstructData(JSC::ConstructData& constructData)
       
  1842 {
       
  1843     constructData.native.function = construct;
       
  1844     return JSC::ConstructTypeHost;
       
  1845 }
       
  1846 
       
  1847 JSC::JSValue JSC_HOST_CALL QMetaObjectWrapperObject::call(
       
  1848     JSC::ExecState *exec, JSC::JSObject *callee,
       
  1849     JSC::JSValue thisValue, const JSC::ArgList &args)
       
  1850 {
       
  1851     QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
       
  1852     thisValue = eng_p->toUsableValue(thisValue);
       
  1853     if (!callee->inherits(&QMetaObjectWrapperObject::info))
       
  1854         return throwError(exec, JSC::TypeError, "callee is not a QMetaObject");
       
  1855     QMetaObjectWrapperObject *self =  static_cast<QMetaObjectWrapperObject*>(callee);
       
  1856     JSC::ExecState *previousFrame = eng_p->currentFrame;
       
  1857     eng_p->pushContext(exec, thisValue, args, callee);
       
  1858     JSC::JSValue result = self->execute(eng_p->currentFrame, args);
       
  1859     eng_p->popContext();
       
  1860     eng_p->currentFrame = previousFrame;
       
  1861     return result;
       
  1862 }
       
  1863 
       
  1864 JSC::JSObject* QMetaObjectWrapperObject::construct(JSC::ExecState *exec, JSC::JSObject *callee, const JSC::ArgList &args)
       
  1865 {
       
  1866     QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee);
       
  1867     QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
       
  1868     JSC::ExecState *previousFrame = eng_p->currentFrame;
       
  1869     eng_p->pushContext(exec, JSC::JSValue(), args, callee, true);
       
  1870     JSC::JSValue result = self->execute(eng_p->currentFrame, args);
       
  1871     eng_p->popContext();
       
  1872     eng_p->currentFrame = previousFrame;
       
  1873     if (!result || !result.isObject())
       
  1874         return 0;
       
  1875     return JSC::asObject(result);
       
  1876 }
       
  1877 
       
  1878 JSC::JSValue QMetaObjectWrapperObject::execute(JSC::ExecState *exec,
       
  1879                                                const JSC::ArgList &args)
       
  1880 {
       
  1881     if (data->ctor) {
       
  1882         QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
       
  1883         QScriptContext *ctx = eng_p->contextForFrame(exec);
       
  1884         JSC::CallData callData;
       
  1885         JSC::CallType callType = data->ctor.getCallData(callData);
       
  1886         Q_UNUSED(callType);
       
  1887         Q_ASSERT_X(callType == JSC::CallTypeHost, Q_FUNC_INFO, "script constructors not supported");
       
  1888         if (data->ctor.inherits(&FunctionWithArgWrapper::info)) {
       
  1889             FunctionWithArgWrapper *wrapper = static_cast<FunctionWithArgWrapper*>(JSC::asObject(data->ctor));
       
  1890             QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(eng_p), wrapper->arg());
       
  1891             return eng_p->scriptValueToJSCValue(result);
       
  1892         } else {
       
  1893             Q_ASSERT(data->ctor.inherits(&FunctionWrapper::info));
       
  1894             FunctionWrapper *wrapper = static_cast<FunctionWrapper*>(JSC::asObject(data->ctor));
       
  1895             QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(eng_p));
       
  1896             return eng_p->scriptValueToJSCValue(result);
       
  1897         }
       
  1898     } else {
       
  1899         const QMetaObject *meta = data->value;
       
  1900         if (meta->constructorCount() > 0) {
       
  1901             JSC::JSValue result = callQtMethod(exec, QMetaMethod::Constructor, /*thisQObject=*/0,
       
  1902                                                args, meta, meta->constructorCount()-1, /*maybeOverloaded=*/true);
       
  1903             if (!exec->hadException()) {
       
  1904                 Q_ASSERT(result && result.inherits(&QScriptObject::info));
       
  1905                 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(result));
       
  1906                 QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(object->delegate());
       
  1907                 delegate->setOwnership(QScriptEngine::AutoOwnership);
       
  1908                 if (data->prototype)
       
  1909                     object->setPrototype(data->prototype);
       
  1910             }
       
  1911             return result;
       
  1912         } else {
       
  1913             QString message = QString::fromLatin1("no constructor for %0")
       
  1914                               .arg(QLatin1String(meta->className()));
       
  1915             return JSC::throwError(exec, JSC::TypeError, message);
       
  1916         }
       
  1917     }
       
  1918 }
       
  1919 
       
  1920 struct StaticQtMetaObject : public QObject
       
  1921 {
       
  1922     static const QMetaObject *get()
       
  1923         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
       
  1924 };
       
  1925 
       
  1926 static JSC::JSValue JSC_HOST_CALL qmetaobjectProtoFuncClassName(
       
  1927     JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&)
       
  1928 {
       
  1929     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
       
  1930     thisValue = engine->toUsableValue(thisValue);
       
  1931     if (!thisValue.inherits(&QMetaObjectWrapperObject::info))
       
  1932         return throwError(exec, JSC::TypeError, "this object is not a QMetaObject");
       
  1933     const QMetaObject *meta = static_cast<QMetaObjectWrapperObject*>(JSC::asObject(thisValue))->value();
       
  1934     return JSC::jsString(exec, meta->className());
       
  1935 }
       
  1936 
       
  1937 QMetaObjectPrototype::QMetaObjectPrototype(
       
  1938     JSC::ExecState *exec, WTF::PassRefPtr<JSC::Structure> structure,
       
  1939     JSC::Structure* prototypeFunctionStructure)
       
  1940     : QMetaObjectWrapperObject(exec, StaticQtMetaObject::get(), /*ctor=*/JSC::JSValue(), structure)
       
  1941 {
       
  1942     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, JSC::Identifier(exec, "className"), qmetaobjectProtoFuncClassName), JSC::DontEnum);
       
  1943 }
       
  1944 
       
  1945 static const uint qt_meta_data_QObjectConnectionManager[] = {
       
  1946 
       
  1947  // content:
       
  1948        1,       // revision
       
  1949        0,       // classname
       
  1950        0,    0, // classinfo
       
  1951        1,   10, // methods
       
  1952        0,    0, // properties
       
  1953        0,    0, // enums/sets
       
  1954 
       
  1955  // slots: signature, parameters, type, tag, flags
       
  1956       35,   34,   34,   34, 0x0a,
       
  1957 
       
  1958        0        // eod
       
  1959 };
       
  1960 
       
  1961 static const char qt_meta_stringdata_QObjectConnectionManager[] = {
       
  1962     "QScript::QObjectConnectionManager\0\0execute()\0"
       
  1963 };
       
  1964 
       
  1965 const QMetaObject QObjectConnectionManager::staticMetaObject = {
       
  1966     { &QObject::staticMetaObject, qt_meta_stringdata_QObjectConnectionManager,
       
  1967       qt_meta_data_QObjectConnectionManager, 0 }
       
  1968 };
       
  1969 
       
  1970 const QMetaObject *QObjectConnectionManager::metaObject() const
       
  1971 {
       
  1972     return &staticMetaObject;
       
  1973 }
       
  1974 
       
  1975 void *QObjectConnectionManager::qt_metacast(const char *_clname)
       
  1976 {
       
  1977     if (!_clname) return 0;
       
  1978     if (!strcmp(_clname, qt_meta_stringdata_QObjectConnectionManager))
       
  1979         return static_cast<void*>(const_cast<QObjectConnectionManager*>(this));
       
  1980     return QObject::qt_metacast(_clname);
       
  1981 }
       
  1982 
       
  1983 int QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
       
  1984 {
       
  1985     _id = QObject::qt_metacall(_c, _id, _a);
       
  1986     if (_id < 0)
       
  1987         return _id;
       
  1988     if (_c == QMetaObject::InvokeMetaMethod) {
       
  1989         execute(_id, _a);
       
  1990         _id -= slotCounter;
       
  1991     }
       
  1992     return _id;
       
  1993 }
       
  1994 
       
  1995 void QObjectConnectionManager::execute(int slotIndex, void **argv)
       
  1996 {
       
  1997     JSC::JSValue receiver;
       
  1998     JSC::JSValue slot;
       
  1999     JSC::JSValue senderWrapper;
       
  2000     int signalIndex = -1;
       
  2001     for (int i = 0; i < connections.size(); ++i) {
       
  2002         const QVector<QObjectConnection> &cs = connections.at(i);
       
  2003         for (int j = 0; j < cs.size(); ++j) {
       
  2004             const QObjectConnection &c = cs.at(j);
       
  2005             if (c.slotIndex == slotIndex) {
       
  2006                 receiver = c.receiver;
       
  2007                 slot = c.slot;
       
  2008                 senderWrapper = c.senderWrapper;
       
  2009                 signalIndex = i;
       
  2010                 break;
       
  2011             }
       
  2012         }
       
  2013     }
       
  2014     Q_ASSERT(slot && slot.isObject());
       
  2015 
       
  2016     if (engine->isCollecting()) {
       
  2017         qWarning("QtScript: can't execute signal handler during GC");
       
  2018         // we can't do a script function call during GC,
       
  2019         // so we're forced to ignore this signal
       
  2020         return;
       
  2021     }
       
  2022 
       
  2023 #if 0
       
  2024     QScriptFunction *fun = engine->convertToNativeFunction(slot);
       
  2025     if (fun == 0) {
       
  2026         // the signal handler has been GC'ed. This can only happen when
       
  2027         // a QObject is owned by the engine, the engine is destroyed, and
       
  2028         // there is a script function connected to the destroyed() signal
       
  2029         Q_ASSERT(signalIndex <= 1); // destroyed(QObject*)
       
  2030         return;
       
  2031     }
       
  2032 #endif
       
  2033 
       
  2034     const QMetaObject *meta = sender()->metaObject();
       
  2035     const QMetaMethod method = meta->method(signalIndex);
       
  2036 
       
  2037     QList<QByteArray> parameterTypes = method.parameterTypes();
       
  2038     int argc = parameterTypes.count();
       
  2039 
       
  2040     JSC::ExecState *exec = engine->currentFrame;
       
  2041     QVarLengthArray<JSC::JSValue, 8> argsVector(argc);
       
  2042     for (int i = 0; i < argc; ++i) {
       
  2043         // ### optimize -- no need to convert via QScriptValue
       
  2044         QScriptValue actual;
       
  2045         void *arg = argv[i + 1];
       
  2046         QByteArray typeName = parameterTypes.at(i);
       
  2047         int argType = QMetaType::type(parameterTypes.at(i));
       
  2048         if (!argType) {
       
  2049             if (typeName == "QVariant") {
       
  2050                 actual = engine->scriptValueFromVariant(*reinterpret_cast<QVariant*>(arg));
       
  2051             } else {
       
  2052                 qWarning("QScriptEngine: Unable to handle unregistered datatype '%s' "
       
  2053                          "when invoking handler of signal %s::%s",
       
  2054                          typeName.constData(), meta->className(), method.signature());
       
  2055                 actual = QScriptValue(QScriptValue::UndefinedValue);
       
  2056             }
       
  2057         } else {
       
  2058             actual = engine->create(argType, arg);
       
  2059         }
       
  2060         argsVector[i] = engine->scriptValueToJSCValue(actual);
       
  2061     }
       
  2062     JSC::ArgList jscArgs(argsVector.data(), argsVector.size());
       
  2063 
       
  2064     JSC::JSValue senderObject;
       
  2065     if (senderWrapper && senderWrapper.inherits(&QScriptObject::info)) // ### check if it's actually a QObject wrapper
       
  2066         senderObject = senderWrapper;
       
  2067     else {
       
  2068         QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
       
  2069         senderObject = engine->newQObject(sender(), QScriptEngine::QtOwnership, opt);
       
  2070     }
       
  2071 
       
  2072     JSC::JSValue thisObject;
       
  2073     if (receiver && receiver.isObject())
       
  2074         thisObject = receiver;
       
  2075     else
       
  2076         thisObject = engine->globalObject();
       
  2077 
       
  2078     JSC::CallData callData;
       
  2079     JSC::CallType callType = slot.getCallData(callData);
       
  2080     if (exec->hadException())
       
  2081         exec->clearException(); // ### otherwise JSC asserts
       
  2082     JSC::call(exec, slot, callType, callData, thisObject, jscArgs);
       
  2083 
       
  2084     if (exec->hadException()) {
       
  2085         engine->emitSignalHandlerException();
       
  2086     }
       
  2087 }
       
  2088 
       
  2089 QObjectConnectionManager::QObjectConnectionManager(QScriptEnginePrivate *eng)
       
  2090     : engine(eng), slotCounter(0)
       
  2091 {
       
  2092 }
       
  2093 
       
  2094 QObjectConnectionManager::~QObjectConnectionManager()
       
  2095 {
       
  2096 }
       
  2097 
       
  2098 void QObjectConnectionManager::mark(JSC::MarkStack& markStack)
       
  2099 {
       
  2100     for (int i = 0; i < connections.size(); ++i) {
       
  2101         QVector<QObjectConnection> &cs = connections[i];
       
  2102         for (int j = 0; j < cs.size(); ++j)
       
  2103             cs[j].mark(markStack);
       
  2104     }
       
  2105 }
       
  2106 
       
  2107 bool QObjectConnectionManager::addSignalHandler(
       
  2108     QObject *sender, int signalIndex, JSC::JSValue receiver,
       
  2109     JSC::JSValue function, JSC::JSValue senderWrapper,
       
  2110     Qt::ConnectionType type)
       
  2111 {
       
  2112     if (connections.size() <= signalIndex)
       
  2113         connections.resize(signalIndex+1);
       
  2114     QVector<QObjectConnection> &cs = connections[signalIndex];
       
  2115     int absSlotIndex = slotCounter + metaObject()->methodOffset();
       
  2116     bool ok = QMetaObject::connect(sender, signalIndex, this, absSlotIndex, type);
       
  2117     if (ok) {
       
  2118         cs.append(QObjectConnection(slotCounter++, receiver, function, senderWrapper));
       
  2119         QMetaMethod signal = sender->metaObject()->method(signalIndex);
       
  2120         QByteArray signalString;
       
  2121         signalString.append('2'); // signal code
       
  2122         signalString.append(signal.signature());
       
  2123         static_cast<QObjectNotifyCaller*>(sender)->callConnectNotify(signalString);
       
  2124     }
       
  2125     return ok;
       
  2126 }
       
  2127 
       
  2128 bool QObjectConnectionManager::removeSignalHandler(
       
  2129     QObject *sender, int signalIndex,
       
  2130     JSC::JSValue receiver, JSC::JSValue slot)
       
  2131 {
       
  2132     if (connections.size() <= signalIndex)
       
  2133         return false;
       
  2134     QVector<QObjectConnection> &cs = connections[signalIndex];
       
  2135     for (int i = 0; i < cs.size(); ++i) {
       
  2136         const QObjectConnection &c = cs.at(i);
       
  2137         if (c.hasTarget(receiver, slot)) {
       
  2138             int absSlotIndex = c.slotIndex + metaObject()->methodOffset();
       
  2139             bool ok = QMetaObject::disconnect(sender, signalIndex, this, absSlotIndex);
       
  2140             if (ok) {
       
  2141                 cs.remove(i);
       
  2142                 QMetaMethod signal = sender->metaObject()->method(signalIndex);
       
  2143                 QByteArray signalString;
       
  2144                 signalString.append('2'); // signal code
       
  2145                 signalString.append(signal.signature());
       
  2146                 static_cast<QScript::QObjectNotifyCaller*>(sender)->callDisconnectNotify(signalString);
       
  2147             }
       
  2148             return ok;
       
  2149         }
       
  2150     }
       
  2151     return false;
       
  2152 }
       
  2153 
       
  2154 QObjectData::QObjectData(QScriptEnginePrivate *eng)
       
  2155     : engine(eng), connectionManager(0)
       
  2156 {
       
  2157 }
       
  2158 
       
  2159 QObjectData::~QObjectData()
       
  2160 {
       
  2161     if (connectionManager) {
       
  2162         delete connectionManager;
       
  2163         connectionManager = 0;
       
  2164     }
       
  2165 }
       
  2166 
       
  2167 void QObjectData::mark(JSC::MarkStack& markStack)
       
  2168 {
       
  2169     if (connectionManager)
       
  2170         connectionManager->mark(markStack);
       
  2171     {
       
  2172         QList<QScript::QObjectWrapperInfo>::iterator it;
       
  2173         for (it = wrappers.begin(); it != wrappers.end(); ) {
       
  2174             const QScript::QObjectWrapperInfo &info = *it;
       
  2175             // ### don't mark if there are no other references.
       
  2176             // we need something like isMarked()
       
  2177             markStack.append(info.object);
       
  2178             ++it;
       
  2179         }
       
  2180     }
       
  2181 }
       
  2182 
       
  2183 bool QObjectData::addSignalHandler(QObject *sender,
       
  2184                                    int signalIndex,
       
  2185                                    JSC::JSValue receiver,
       
  2186                                    JSC::JSValue slot,
       
  2187                                    JSC::JSValue senderWrapper,
       
  2188                                    Qt::ConnectionType type)
       
  2189 {
       
  2190     if (!connectionManager)
       
  2191         connectionManager = new QObjectConnectionManager(engine);
       
  2192     return connectionManager->addSignalHandler(
       
  2193         sender, signalIndex, receiver, slot, senderWrapper, type);
       
  2194 }
       
  2195 
       
  2196 bool QObjectData::removeSignalHandler(QObject *sender,
       
  2197                                       int signalIndex,
       
  2198                                       JSC::JSValue receiver,
       
  2199                                       JSC::JSValue slot)
       
  2200 {
       
  2201     if (!connectionManager)
       
  2202         return false;
       
  2203     return connectionManager->removeSignalHandler(
       
  2204         sender, signalIndex, receiver, slot);
       
  2205 }
       
  2206 
       
  2207 QScriptObject *QObjectData::findWrapper(QScriptEngine::ValueOwnership ownership,
       
  2208                                         const QScriptEngine::QObjectWrapOptions &options) const
       
  2209 {
       
  2210     for (int i = 0; i < wrappers.size(); ++i) {
       
  2211         const QObjectWrapperInfo &info = wrappers.at(i);
       
  2212         if ((info.ownership == ownership) && (info.options == options))
       
  2213             return info.object;
       
  2214     }
       
  2215     return 0;
       
  2216 }
       
  2217 
       
  2218 void QObjectData::registerWrapper(QScriptObject *wrapper,
       
  2219                                   QScriptEngine::ValueOwnership ownership,
       
  2220                                   const QScriptEngine::QObjectWrapOptions &options)
       
  2221 {
       
  2222     wrappers.append(QObjectWrapperInfo(wrapper, ownership, options));
       
  2223 }
       
  2224 
       
  2225 } // namespace QScript
       
  2226 
       
  2227 QT_END_NAMESPACE
       
  2228 
       
  2229 namespace JSC
       
  2230 {
       
  2231     ASSERT_CLASS_FITS_IN_CELL(QScript::QtFunction);
       
  2232 }
       
  2233 
       
  2234 #include "moc_qscriptqobject_p.cpp"
       
  2235