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