• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  *  This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  */
19 
20 #include "config.h"
21 #include "qt_runtime.h"
22 
23 #include "BooleanObject.h"
24 #include "DateInstance.h"
25 #include "DateMath.h"
26 #include "DatePrototype.h"
27 #include "DumpRenderTreeSupportQt.h"
28 #include "FunctionPrototype.h"
29 #include "Interpreter.h"
30 #include "JSArray.h"
31 #include "JSByteArray.h"
32 #include "JSDocument.h"
33 #include "JSDOMBinding.h"
34 #include "JSDOMWindow.h"
35 #include <JSFunction.h>
36 #include "JSGlobalObject.h"
37 #include "JSHTMLElement.h"
38 #include "JSLock.h"
39 #include "JSObject.h"
40 #include "ObjectPrototype.h"
41 #include "PropertyNameArray.h"
42 #include "RegExpConstructor.h"
43 #include "RegExpObject.h"
44 #include "qdatetime.h"
45 #include "qdebug.h"
46 #include "qmetaobject.h"
47 #include "qmetatype.h"
48 #include "qobject.h"
49 #include "qstringlist.h"
50 #include "qt_instance.h"
51 #include "qt_pixmapruntime.h"
52 #include "qvarlengtharray.h"
53 #include "qwebelement.h"
54 #include <limits.h>
55 #include <runtime/Error.h>
56 #include <runtime_array.h>
57 #include <runtime_object.h>
58 
59 // QtScript has these
60 Q_DECLARE_METATYPE(QObjectList);
61 Q_DECLARE_METATYPE(QList<int>);
62 Q_DECLARE_METATYPE(QVariant);
63 
64 using namespace WebCore;
65 
66 namespace JSC {
67 namespace Bindings {
68 
69 // Debugging
70 //#define QTWK_RUNTIME_CONVERSION_DEBUG
71 //#define QTWK_RUNTIME_MATCH_DEBUG
72 
73 class QWKNoDebug
74 {
75 public:
QWKNoDebug()76     inline QWKNoDebug(){}
~QWKNoDebug()77     inline ~QWKNoDebug(){}
78 
79     template<typename T>
operator <<(const T &)80     inline QWKNoDebug &operator<<(const T &) { return *this; }
81 };
82 
83 #ifdef QTWK_RUNTIME_CONVERSION_DEBUG
84 #define qConvDebug() qDebug()
85 #else
86 #define qConvDebug() QWKNoDebug()
87 #endif
88 
89 #ifdef QTWK_RUNTIME_MATCH_DEBUG
90 #define qMatchDebug() qDebug()
91 #else
92 #define qMatchDebug() QWKNoDebug()
93 #endif
94 
95 typedef enum {
96     Variant = 0,
97     Number,
98     Boolean,
99     String,
100     Date,
101     RegExp,
102     Array,
103     QObj,
104     Object,
105     Null,
106     RTArray,
107     JSByteArray
108 } JSRealType;
109 
110 #if defined(QTWK_RUNTIME_CONVERSION_DEBUG) || defined(QTWK_RUNTIME_MATCH_DEBUG)
operator <<(QDebug dbg,const JSRealType & c)111 QDebug operator<<(QDebug dbg, const JSRealType &c)
112 {
113      const char *map[] = { "Variant", "Number", "Boolean", "String", "Date",
114          "RegExp", "Array", "RTObject", "Object", "Null", "RTArray"};
115 
116      dbg.nospace() << "JSType(" << ((int)c) << ", " <<  map[c] << ")";
117 
118      return dbg.space();
119 }
120 #endif
121 
122 // this is here as a proxy, so we'd have a class to friend in QWebElement,
123 // as getting/setting a WebCore in QWebElement is private
124 class QtWebElementRuntime {
125 public:
create(Element * element)126     static QWebElement create(Element* element)
127     {
128         return QWebElement(element);
129     }
130 
get(const QWebElement & element)131     static Element* get(const QWebElement& element)
132     {
133         return element.m_element;
134     }
135 };
136 
137 // this is here as a proxy, so we'd have a class to friend in QDRTNode,
138 // as getting/setting a WebCore in QDRTNode is private.
139 // We only need to pass WebCore Nodes for layout tests.
140 class QtDRTNodeRuntime {
141 public:
create(Node * node)142     static QDRTNode create(Node* node)
143     {
144         return QDRTNode(node);
145     }
146 
get(const QDRTNode & node)147     static Node* get(const QDRTNode& node)
148     {
149         return node.m_node;
150     }
151 };
152 
valueRealType(ExecState * exec,JSValue val)153 static JSRealType valueRealType(ExecState* exec, JSValue val)
154 {
155     if (val.isNumber())
156         return Number;
157     else if (val.isString())
158         return String;
159     else if (val.isBoolean())
160         return Boolean;
161     else if (val.isNull())
162         return Null;
163     else if (isJSByteArray(&exec->globalData(), val))
164         return JSByteArray;
165     else if (val.isObject()) {
166         JSObject *object = val.toObject(exec);
167         if (object->inherits(&RuntimeArray::s_info))  // RuntimeArray 'inherits' from Array, but not in C++
168             return RTArray;
169         else if (object->inherits(&JSArray::s_info))
170             return Array;
171         else if (object->inherits(&DateInstance::s_info))
172             return Date;
173         else if (object->inherits(&RegExpObject::s_info))
174             return RegExp;
175         else if (object->inherits(&RuntimeObject::s_info))
176             return QObj;
177         return Object;
178     }
179 
180     return String; // I don't know.
181 }
182 
convertValueToQVariant(ExecState * exec,JSValue value,QMetaType::Type hint,int * distance,HashSet<JSObject * > * visitedObjects,int recursionLimit)183 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance, HashSet<JSObject*>* visitedObjects, int recursionLimit)
184 {
185     --recursionLimit;
186 
187     if (!value || !recursionLimit)
188         return QVariant();
189 
190     JSObject* object = 0;
191     if (value.isObject()) {
192         object = value.toObject(exec);
193         if (visitedObjects->contains(object))
194             return QVariant();
195 
196         visitedObjects->add(object);
197     }
198 
199     // check magic pointer values before dereferencing value
200     if (value == jsNaN()
201         || (value == jsUndefined()
202             && hint != QMetaType::QString
203             && hint != (QMetaType::Type) qMetaTypeId<QVariant>())) {
204         if (distance)
205             *distance = -1;
206         return QVariant();
207     }
208 
209     JSLock lock(SilenceAssertionsOnly);
210     JSRealType type = valueRealType(exec, value);
211     if (hint == QMetaType::Void) {
212         switch(type) {
213             case Number:
214                 hint = QMetaType::Double;
215                 break;
216             case Boolean:
217                 hint = QMetaType::Bool;
218                 break;
219             case String:
220             default:
221                 hint = QMetaType::QString;
222                 break;
223             case Date:
224                 hint = QMetaType::QDateTime;
225                 break;
226             case RegExp:
227                 hint = QMetaType::QRegExp;
228                 break;
229             case Object:
230                 if (object->inherits(&NumberObject::s_info))
231                     hint = QMetaType::Double;
232                 else if (object->inherits(&BooleanObject::s_info))
233                     hint = QMetaType::Bool;
234                 else
235                     hint = QMetaType::QVariantMap;
236                 break;
237             case QObj:
238                 hint = QMetaType::QObjectStar;
239                 break;
240             case JSByteArray:
241                 hint = QMetaType::QByteArray;
242                 break;
243             case Array:
244             case RTArray:
245                 hint = QMetaType::QVariantList;
246                 break;
247         }
248     }
249 
250     qConvDebug() << "convertValueToQVariant: jstype is " << type << ", hint is" << hint;
251 
252     if (value == jsNull()
253         && hint != QMetaType::QObjectStar
254         && hint != QMetaType::VoidStar
255         && hint != QMetaType::QString
256         && hint != (QMetaType::Type) qMetaTypeId<QVariant>()) {
257         if (distance)
258             *distance = -1;
259         return QVariant();
260     }
261 
262     QVariant ret;
263     int dist = -1;
264     switch (hint) {
265         case QMetaType::Bool:
266             if (type == Object && object->inherits(&BooleanObject::s_info))
267                 ret = QVariant(asBooleanObject(value)->internalValue().toBoolean(exec));
268             else
269                 ret = QVariant(value.toBoolean(exec));
270             if (type == Boolean)
271                 dist = 0;
272             else
273                 dist = 10;
274             break;
275 
276         case QMetaType::Int:
277         case QMetaType::UInt:
278         case QMetaType::Long:
279         case QMetaType::ULong:
280         case QMetaType::LongLong:
281         case QMetaType::ULongLong:
282         case QMetaType::Short:
283         case QMetaType::UShort:
284         case QMetaType::Float:
285         case QMetaType::Double:
286             ret = QVariant(value.toNumber(exec));
287             ret.convert((QVariant::Type)hint);
288             if (type == Number) {
289                 switch (hint) {
290                 case QMetaType::Double:
291                     dist = 0;
292                     break;
293                 case QMetaType::Float:
294                     dist = 1;
295                     break;
296                 case QMetaType::LongLong:
297                 case QMetaType::ULongLong:
298                     dist = 2;
299                     break;
300                 case QMetaType::Long:
301                 case QMetaType::ULong:
302                     dist = 3;
303                     break;
304                 case QMetaType::Int:
305                 case QMetaType::UInt:
306                     dist = 4;
307                     break;
308                 case QMetaType::Short:
309                 case QMetaType::UShort:
310                     dist = 5;
311                     break;
312                     break;
313                 default:
314                     dist = 10;
315                     break;
316                 }
317             } else {
318                 dist = 10;
319             }
320             break;
321 
322         case QMetaType::QChar:
323             if (type == Number || type == Boolean) {
324                 ret = QVariant(QChar((ushort)value.toNumber(exec)));
325                 if (type == Boolean)
326                     dist = 3;
327                 else
328                     dist = 6;
329             } else {
330                 UString str = value.toString(exec);
331                 ret = QVariant(QChar(str.length() ? *(const ushort*)str.impl()->characters() : 0));
332                 if (type == String)
333                     dist = 3;
334                 else
335                     dist = 10;
336             }
337             break;
338 
339         case QMetaType::QString: {
340             if (value.isUndefinedOrNull()) {
341                 if (distance)
342                     *distance = 1;
343                 return QString();
344             } else {
345                 UString ustring = value.toString(exec);
346                 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()));
347                 if (type == String)
348                     dist = 0;
349                 else
350                     dist = 10;
351             }
352             break;
353         }
354 
355         case QMetaType::QVariantMap:
356             if (type == Object || type == Array || type == RTArray) {
357                 // Enumerate the contents of the object
358                 PropertyNameArray properties(exec);
359                 object->getPropertyNames(exec, properties);
360                 PropertyNameArray::const_iterator it = properties.begin();
361 
362                 QVariantMap result;
363                 int objdist = 0;
364                 while(it != properties.end()) {
365                     if (object->propertyIsEnumerable(exec, *it)) {
366                         JSValue val = object->get(exec, *it);
367                         QVariant v = convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
368                         if (objdist >= 0) {
369                             UString ustring = (*it).ustring();
370                             QString id = QString((const QChar*)ustring.impl()->characters(), ustring.length());
371                             result.insert(id, v);
372                         }
373                     }
374                     ++it;
375                 }
376                 dist = 1;
377                 ret = QVariant(result);
378             }
379             break;
380 
381         case QMetaType::QVariantList:
382             if (type == RTArray) {
383                 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
384 
385                 QVariantList result;
386                 int len = rtarray->getLength();
387                 int objdist = 0;
388                 qConvDebug() << "converting a " << len << " length Array";
389                 for (int i = 0; i < len; ++i) {
390                     JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
391                     result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
392                     if (objdist == -1) {
393                         qConvDebug() << "Failed converting element at index " << i;
394                         break; // Failed converting a list entry, so fail the array
395                     }
396                 }
397                 if (objdist != -1) {
398                     dist = 5;
399                     ret = QVariant(result);
400                 }
401             } else if (type == Array) {
402                 JSArray* array = static_cast<JSArray*>(object);
403 
404                 QVariantList result;
405                 int len = array->length();
406                 int objdist = 0;
407                 qConvDebug() << "converting a " << len << " length Array";
408                 for (int i = 0; i < len; ++i) {
409                     JSValue val = array->get(exec, i);
410                     result.append(convertValueToQVariant(exec, val, QMetaType::Void, &objdist, visitedObjects, recursionLimit));
411                     if (objdist == -1) {
412                         qConvDebug() << "Failed converting element at index " << i;
413                         break; // Failed converting a list entry, so fail the array
414                     }
415                 }
416                 if (objdist != -1) {
417                     dist = 5;
418                     ret = QVariant(result);
419                 }
420             } else {
421                 // Make a single length array
422                 int objdist;
423                 qConvDebug() << "making a single length variantlist";
424                 QVariant var = convertValueToQVariant(exec, value, QMetaType::Void, &objdist, visitedObjects, recursionLimit);
425                 if (objdist != -1) {
426                     QVariantList result;
427                     result << var;
428                     ret = QVariant(result);
429                     dist = 10;
430                 } else {
431                     qConvDebug() << "failed making single length varlist";
432                 }
433             }
434             break;
435 
436         case QMetaType::QStringList: {
437             if (type == RTArray) {
438                 RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
439 
440                 QStringList result;
441                 int len = rtarray->getLength();
442                 for (int i = 0; i < len; ++i) {
443                     JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
444                     UString ustring = val.toString(exec);
445                     QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
446 
447                     result.append(qstring);
448                 }
449                 dist = 5;
450                 ret = QVariant(result);
451             } else if (type == Array) {
452                 JSArray* array = static_cast<JSArray*>(object);
453 
454                 QStringList result;
455                 int len = array->length();
456                 for (int i = 0; i < len; ++i) {
457                     JSValue val = array->get(exec, i);
458                     UString ustring = val.toString(exec);
459                     QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
460 
461                     result.append(qstring);
462                 }
463                 dist = 5;
464                 ret = QVariant(result);
465             } else {
466                 // Make a single length array
467                 UString ustring = value.toString(exec);
468                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
469                 QStringList result;
470                 result.append(qstring);
471                 ret = QVariant(result);
472                 dist = 10;
473             }
474             break;
475         }
476 
477         case QMetaType::QByteArray: {
478             if (type == JSByteArray) {
479                 WTF::ByteArray* arr = asByteArray(value)->storage();
480                 ret = QVariant(QByteArray(reinterpret_cast<const char*>(arr->data()), arr->length()));
481                 dist = 0;
482             } else {
483                 UString ustring = value.toString(exec);
484                 ret = QVariant(QString((const QChar*)ustring.impl()->characters(), ustring.length()).toLatin1());
485                 if (type == String)
486                     dist = 5;
487                 else
488                     dist = 10;
489             }
490             break;
491         }
492 
493         case QMetaType::QDateTime:
494         case QMetaType::QDate:
495         case QMetaType::QTime:
496             if (type == Date) {
497                 DateInstance* date = static_cast<DateInstance*>(object);
498                 GregorianDateTime gdt;
499                 msToGregorianDateTime(exec, date->internalNumber(), true, gdt);
500                 if (hint == QMetaType::QDateTime) {
501                     ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
502                     dist = 0;
503                 } else if (hint == QMetaType::QDate) {
504                     ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
505                     dist = 1;
506                 } else {
507                     ret = QTime(gdt.hour + 1900, gdt.minute, gdt.second);
508                     dist = 2;
509                 }
510             } else if (type == Number) {
511                 double b = value.toNumber(exec);
512                 GregorianDateTime gdt;
513                 msToGregorianDateTime(exec, b, true, gdt);
514                 if (hint == QMetaType::QDateTime) {
515                     ret = QDateTime(QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay), QTime(gdt.hour, gdt.minute, gdt.second), Qt::UTC);
516                     dist = 6;
517                 } else if (hint == QMetaType::QDate) {
518                     ret = QDate(gdt.year + 1900, gdt.month + 1, gdt.monthDay);
519                     dist = 8;
520                 } else {
521                     ret = QTime(gdt.hour, gdt.minute, gdt.second);
522                     dist = 10;
523                 }
524 #ifndef QT_NO_DATESTRING
525             } else if (type == String) {
526                 UString ustring = value.toString(exec);
527                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
528 
529                 if (hint == QMetaType::QDateTime) {
530                     QDateTime dt = QDateTime::fromString(qstring, Qt::ISODate);
531                     if (!dt.isValid())
532                         dt = QDateTime::fromString(qstring, Qt::TextDate);
533                     if (!dt.isValid())
534                         dt = QDateTime::fromString(qstring, Qt::SystemLocaleDate);
535                     if (!dt.isValid())
536                         dt = QDateTime::fromString(qstring, Qt::LocaleDate);
537                     if (dt.isValid()) {
538                         ret = dt;
539                         dist = 2;
540                     }
541                 } else if (hint == QMetaType::QDate) {
542                     QDate dt = QDate::fromString(qstring, Qt::ISODate);
543                     if (!dt.isValid())
544                         dt = QDate::fromString(qstring, Qt::TextDate);
545                     if (!dt.isValid())
546                         dt = QDate::fromString(qstring, Qt::SystemLocaleDate);
547                     if (!dt.isValid())
548                         dt = QDate::fromString(qstring, Qt::LocaleDate);
549                     if (dt.isValid()) {
550                         ret = dt;
551                         dist = 3;
552                     }
553                 } else {
554                     QTime dt = QTime::fromString(qstring, Qt::ISODate);
555                     if (!dt.isValid())
556                         dt = QTime::fromString(qstring, Qt::TextDate);
557                     if (!dt.isValid())
558                         dt = QTime::fromString(qstring, Qt::SystemLocaleDate);
559                     if (!dt.isValid())
560                         dt = QTime::fromString(qstring, Qt::LocaleDate);
561                     if (dt.isValid()) {
562                         ret = dt;
563                         dist = 3;
564                     }
565                 }
566 #endif // QT_NO_DATESTRING
567             }
568             break;
569 
570         case QMetaType::QRegExp:
571             if (type == RegExp) {
572 /*
573                 RegExpObject *re = static_cast<RegExpObject*>(object);
574 */
575                 // Attempt to convert.. a bit risky
576                 UString ustring = value.toString(exec);
577                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
578 
579                 // this is of the form '/xxxxxx/i'
580                 int firstSlash = qstring.indexOf(QLatin1Char('/'));
581                 int lastSlash = qstring.lastIndexOf(QLatin1Char('/'));
582                 if (firstSlash >=0 && lastSlash > firstSlash) {
583                     QRegExp realRe;
584 
585                     realRe.setPattern(qstring.mid(firstSlash + 1, lastSlash - firstSlash - 1));
586 
587                     if (qstring.mid(lastSlash + 1).contains(QLatin1Char('i')))
588                         realRe.setCaseSensitivity(Qt::CaseInsensitive);
589 
590                     ret = QVariant::fromValue(realRe);
591                     dist = 0;
592                 } else {
593                     qConvDebug() << "couldn't parse a JS regexp";
594                 }
595             } else if (type == String) {
596                 UString ustring = value.toString(exec);
597                 QString qstring = QString((const QChar*)ustring.impl()->characters(), ustring.length());
598 
599                 QRegExp re(qstring);
600                 if (re.isValid()) {
601                     ret = QVariant::fromValue(re);
602                     dist = 10;
603                 }
604             }
605             break;
606 
607         case QMetaType::QObjectStar:
608             if (type == QObj) {
609                 QtInstance* qtinst = QtInstance::getInstance(object);
610                 if (qtinst) {
611                     if (qtinst->getObject()) {
612                         qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
613                         ret = QVariant::fromValue(qtinst->getObject());
614                         qConvDebug() << ret;
615                         dist = 0;
616                     } else {
617                         qConvDebug() << "can't convert deleted qobject";
618                     }
619                 } else {
620                     qConvDebug() << "wasn't a qtinstance";
621                 }
622             } else if (type == Null) {
623                 QObject* nullobj = 0;
624                 ret = QVariant::fromValue(nullobj);
625                 dist = 0;
626             } else {
627                 qConvDebug() << "previous type was not an object:" << type;
628             }
629             break;
630 
631         case QMetaType::VoidStar:
632             if (type == QObj) {
633                 QtInstance* qtinst = QtInstance::getInstance(object);
634                 if (qtinst) {
635                     if (qtinst->getObject()) {
636                         qConvDebug() << "found instance, with object:" << (void*) qtinst->getObject();
637                         ret = QVariant::fromValue((void *)qtinst->getObject());
638                         qConvDebug() << ret;
639                         dist = 0;
640                     } else {
641                         qConvDebug() << "can't convert deleted qobject";
642                     }
643                 } else {
644                     qConvDebug() << "wasn't a qtinstance";
645                 }
646             } else if (type == Null) {
647                 ret = QVariant::fromValue((void*)0);
648                 dist = 0;
649             } else if (type == Number) {
650                 // I don't think that converting a double to a pointer is a wise
651                 // move.  Except maybe 0.
652                 qConvDebug() << "got number for void * - not converting, seems unsafe:" << value.toNumber(exec);
653             } else {
654                 qConvDebug() << "void* - unhandled type" << type;
655             }
656             break;
657 
658         default:
659             // Non const type ids
660             if (hint == (QMetaType::Type) qMetaTypeId<QObjectList>())
661             {
662                 if (type == RTArray) {
663                     RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
664 
665                     QObjectList result;
666                     int len = rtarray->getLength();
667                     for (int i = 0; i < len; ++i) {
668                         JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
669                         int itemdist = -1;
670                         QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
671                         if (itemdist >= 0)
672                             result.append(item.value<QObject*>());
673                         else
674                             break;
675                     }
676                     // If we didn't fail conversion
677                     if (result.count() == len) {
678                         dist = 5;
679                         ret = QVariant::fromValue(result);
680                     }
681                 } else if (type == Array) {
682                     JSObject* object = value.toObject(exec);
683                     JSArray* array = static_cast<JSArray *>(object);
684                     QObjectList result;
685                     int len = array->length();
686                     for (int i = 0; i < len; ++i) {
687                         JSValue val = array->get(exec, i);
688                         int itemdist = -1;
689                         QVariant item = convertValueToQVariant(exec, val, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
690                         if (itemdist >= 0)
691                             result.append(item.value<QObject*>());
692                         else
693                             break;
694                     }
695                     // If we didn't fail conversion
696                     if (result.count() == len) {
697                         dist = 5;
698                         ret = QVariant::fromValue(result);
699                     }
700                 } else {
701                     // Make a single length array
702                     QObjectList result;
703                     int itemdist = -1;
704                     QVariant item = convertValueToQVariant(exec, value, QMetaType::QObjectStar, &itemdist, visitedObjects, recursionLimit);
705                     if (itemdist >= 0) {
706                         result.append(item.value<QObject*>());
707                         dist = 10;
708                         ret = QVariant::fromValue(result);
709                     }
710                 }
711                 break;
712             } else if (hint == (QMetaType::Type) qMetaTypeId<QList<int> >()) {
713                 if (type == RTArray) {
714                     RuntimeArray* rtarray = static_cast<RuntimeArray*>(object);
715 
716                     QList<int> result;
717                     int len = rtarray->getLength();
718                     for (int i = 0; i < len; ++i) {
719                         JSValue val = rtarray->getConcreteArray()->valueAt(exec, i);
720                         int itemdist = -1;
721                         QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
722                         if (itemdist >= 0)
723                             result.append(item.value<int>());
724                         else
725                             break;
726                     }
727                     // If we didn't fail conversion
728                     if (result.count() == len) {
729                         dist = 5;
730                         ret = QVariant::fromValue(result);
731                     }
732                 } else if (type == Array) {
733                     JSArray* array = static_cast<JSArray *>(object);
734 
735                     QList<int> result;
736                     int len = array->length();
737                     for (int i = 0; i < len; ++i) {
738                         JSValue val = array->get(exec, i);
739                         int itemdist = -1;
740                         QVariant item = convertValueToQVariant(exec, val, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
741                         if (itemdist >= 0)
742                             result.append(item.value<int>());
743                         else
744                             break;
745                     }
746                     // If we didn't fail conversion
747                     if (result.count() == len) {
748                         dist = 5;
749                         ret = QVariant::fromValue(result);
750                     }
751                 } else {
752                     // Make a single length array
753                     QList<int> result;
754                     int itemdist = -1;
755                     QVariant item = convertValueToQVariant(exec, value, QMetaType::Int, &itemdist, visitedObjects, recursionLimit);
756                     if (itemdist >= 0) {
757                         result.append(item.value<int>());
758                         dist = 10;
759                         ret = QVariant::fromValue(result);
760                     }
761                 }
762                 break;
763             } else if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(hint))) {
764                 ret = QtPixmapInstance::variantFromObject(object, static_cast<QMetaType::Type>(hint));
765             } else if (hint == (QMetaType::Type) qMetaTypeId<QWebElement>()) {
766                 if (object && object->inherits(&JSHTMLElement::s_info))
767                     ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSHTMLElement*>(object))->impl()));
768                 else if (object && object->inherits(&JSDocument::s_info))
769                     ret = QVariant::fromValue<QWebElement>(QtWebElementRuntime::create((static_cast<JSDocument*>(object))->impl()->documentElement()));
770                 else
771                     ret = QVariant::fromValue<QWebElement>(QWebElement());
772             } else if (hint == (QMetaType::Type) qMetaTypeId<QDRTNode>()) {
773                 if (object && object->inherits(&JSNode::s_info))
774                     ret = QVariant::fromValue<QDRTNode>(QtDRTNodeRuntime::create((static_cast<JSNode*>(object))->impl()));
775             } else if (hint == (QMetaType::Type) qMetaTypeId<QVariant>()) {
776                 if (value.isUndefinedOrNull()) {
777                     if (distance)
778                         *distance = 1;
779                     return QVariant();
780                 } else {
781                     if (type == Object) {
782                         // Since we haven't really visited this object yet, we remove it
783                         visitedObjects->remove(object);
784                     }
785 
786                     // And then recurse with the autodetect flag
787                     ret = convertValueToQVariant(exec, value, QMetaType::Void, distance, visitedObjects, recursionLimit);
788                     dist = 10;
789                 }
790                 break;
791             }
792 
793             dist = 10;
794             break;
795     }
796 
797     if (!ret.isValid())
798         dist = -1;
799     if (distance)
800         *distance = dist;
801 
802     return ret;
803 }
804 
convertValueToQVariant(ExecState * exec,JSValue value,QMetaType::Type hint,int * distance)805 QVariant convertValueToQVariant(ExecState* exec, JSValue value, QMetaType::Type hint, int *distance)
806 {
807     const int recursionLimit = 200;
808     HashSet<JSObject*> visitedObjects;
809     return convertValueToQVariant(exec, value, hint, distance, &visitedObjects, recursionLimit);
810 }
811 
convertQVariantToValue(ExecState * exec,PassRefPtr<RootObject> root,const QVariant & variant)812 JSValue convertQVariantToValue(ExecState* exec, PassRefPtr<RootObject> root, const QVariant& variant)
813 {
814     // Variants with QObject * can be isNull but not a null pointer
815     // An empty QString variant is also null
816     QMetaType::Type type = (QMetaType::Type) variant.userType();
817 
818     qConvDebug() << "convertQVariantToValue: metatype:" << type << ", isnull: " << variant.isNull();
819     if (variant.isNull() &&
820         type != QMetaType::QObjectStar &&
821         type != QMetaType::VoidStar &&
822         type != QMetaType::QWidgetStar &&
823         type != QMetaType::QString) {
824         return jsNull();
825     }
826 
827     JSLock lock(SilenceAssertionsOnly);
828 
829     if (type == QMetaType::Bool)
830         return jsBoolean(variant.toBool());
831 
832     if (type == QMetaType::Int ||
833         type == QMetaType::UInt ||
834         type == QMetaType::Long ||
835         type == QMetaType::ULong ||
836         type == QMetaType::LongLong ||
837         type == QMetaType::ULongLong ||
838         type == QMetaType::Short ||
839         type == QMetaType::UShort ||
840         type == QMetaType::Float ||
841         type == QMetaType::Double)
842         return jsNumber(variant.toDouble());
843 
844     if (type == QMetaType::QRegExp) {
845         QRegExp re = variant.value<QRegExp>();
846 
847         if (re.isValid()) {
848             UString pattern((UChar*)re.pattern().utf16(), re.pattern().length());
849             RegExpFlags flags = (re.caseSensitivity() == Qt::CaseInsensitive) ? FlagIgnoreCase : NoFlags;
850 
851             RefPtr<JSC::RegExp> regExp = JSC::RegExp::create(&exec->globalData(), pattern, flags);
852             if (regExp->isValid())
853                 return new (exec) RegExpObject(exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp.release());
854             return jsNull();
855         }
856     }
857 
858     if (type == QMetaType::QDateTime ||
859         type == QMetaType::QDate ||
860         type == QMetaType::QTime) {
861 
862         QDate date = QDate::currentDate();
863         QTime time(0,0,0); // midnight
864 
865         if (type == QMetaType::QDate)
866             date = variant.value<QDate>();
867         else if (type == QMetaType::QTime)
868             time = variant.value<QTime>();
869         else {
870             QDateTime dt = variant.value<QDateTime>().toLocalTime();
871             date = dt.date();
872             time = dt.time();
873         }
874 
875         // Dates specified this way are in local time (we convert DateTimes above)
876         GregorianDateTime dt;
877         dt.year = date.year() - 1900;
878         dt.month = date.month() - 1;
879         dt.monthDay = date.day();
880         dt.hour = time.hour();
881         dt.minute = time.minute();
882         dt.second = time.second();
883         dt.isDST = -1;
884         double ms = gregorianDateTimeToMS(exec, dt, time.msec(), /*inputIsUTC*/ false);
885 
886         return new (exec) DateInstance(exec, exec->lexicalGlobalObject()->dateStructure(), trunc(ms));
887     }
888 
889     if (type == QMetaType::QByteArray) {
890         QByteArray qtByteArray = variant.value<QByteArray>();
891         WTF::RefPtr<WTF::ByteArray> wtfByteArray = WTF::ByteArray::create(qtByteArray.length());
892         memcpy(wtfByteArray->data(), qtByteArray.constData(), qtByteArray.length());
893         return new (exec) JSC::JSByteArray(exec, JSC::JSByteArray::createStructure(exec->globalData(), jsNull()), wtfByteArray.get());
894     }
895 
896     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
897         QObject* obj = variant.value<QObject*>();
898         if (!obj)
899             return jsNull();
900         return QtInstance::getQtInstance(obj, root, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
901     }
902 
903     if (QtPixmapInstance::canHandle(static_cast<QMetaType::Type>(variant.type())))
904         return QtPixmapInstance::createPixmapRuntimeObject(exec, root, variant);
905 
906     if (type == qMetaTypeId<QWebElement>()) {
907         if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
908             return jsUndefined();
909 
910         Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
911         if (!document)
912             return jsUndefined();
913 
914         return toJS(exec, toJSDOMGlobalObject(document, exec), QtWebElementRuntime::get(variant.value<QWebElement>()));
915     }
916 
917     if (type == qMetaTypeId<QDRTNode>()) {
918         if (!root->globalObject()->inherits(&JSDOMWindow::s_info))
919             return jsUndefined();
920 
921         Document* document = (static_cast<JSDOMWindow*>(root->globalObject()))->impl()->document();
922         if (!document)
923             return jsUndefined();
924 
925         return toJS(exec, toJSDOMGlobalObject(document, exec), QtDRTNodeRuntime::get(variant.value<QDRTNode>()));
926     }
927 
928     if (type == QMetaType::QVariantMap) {
929         // create a new object, and stuff properties into it
930         JSObject* ret = constructEmptyObject(exec);
931         QVariantMap map = variant.value<QVariantMap>();
932         QVariantMap::const_iterator i = map.constBegin();
933         while (i != map.constEnd()) {
934             QString s = i.key();
935             JSValue val = convertQVariantToValue(exec, root.get(), i.value());
936             if (val) {
937                 PutPropertySlot slot;
938                 ret->put(exec, Identifier(exec, reinterpret_cast_ptr<const UChar *>(s.constData()), s.length()), val, slot);
939                 // ### error case?
940             }
941             ++i;
942         }
943 
944         return ret;
945     }
946 
947     // List types
948     if (type == QMetaType::QVariantList) {
949         QVariantList vl = variant.toList();
950         qConvDebug() << "got a " << vl.count() << " length list:" << vl;
951         return new (exec) RuntimeArray(exec, new QtArray<QVariant>(vl, QMetaType::Void, root));
952     } else if (type == QMetaType::QStringList) {
953         QStringList sl = variant.value<QStringList>();
954         return new (exec) RuntimeArray(exec, new QtArray<QString>(sl, QMetaType::QString, root));
955     } else if (type == (QMetaType::Type) qMetaTypeId<QObjectList>()) {
956         QObjectList ol= variant.value<QObjectList>();
957         return new (exec) RuntimeArray(exec, new QtArray<QObject*>(ol, QMetaType::QObjectStar, root));
958     } else if (type == (QMetaType::Type)qMetaTypeId<QList<int> >()) {
959         QList<int> il= variant.value<QList<int> >();
960         return new (exec) RuntimeArray(exec, new QtArray<int>(il, QMetaType::Int, root));
961     }
962 
963     if (type == (QMetaType::Type)qMetaTypeId<QVariant>()) {
964         QVariant real = variant.value<QVariant>();
965         qConvDebug() << "real variant is:" << real;
966         return convertQVariantToValue(exec, root, real);
967     }
968 
969     qConvDebug() << "fallback path for" << variant << variant.userType();
970 
971     QString string = variant.toString();
972     UString ustring((UChar*)string.utf16(), string.length());
973     return jsString(exec, ustring);
974 }
975 
976 // ===============
977 
978 // Qt-like macros
979 #define QW_D(Class) Class##Data* d = d_func()
980 #define QW_DS(Class,Instance) Class##Data* d = Instance->d_func()
981 
982 const ClassInfo QtRuntimeMethod::s_info = { "QtRuntimeMethod", &InternalFunction::s_info, 0, 0 };
983 
QtRuntimeMethod(QtRuntimeMethodData * dd,ExecState * exec,const Identifier & ident,PassRefPtr<QtInstance> inst)984 QtRuntimeMethod::QtRuntimeMethod(QtRuntimeMethodData* dd, ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst)
985     : InternalFunction(&exec->globalData(), exec->lexicalGlobalObject(), deprecatedGetDOMStructure<QtRuntimeMethod>(exec), ident)
986     , d_ptr(dd)
987 {
988     QW_D(QtRuntimeMethod);
989     d->m_instance = inst;
990 }
991 
~QtRuntimeMethod()992 QtRuntimeMethod::~QtRuntimeMethod()
993 {
994     QW_D(QtRuntimeMethod);
995     d->m_instance->removeCachedMethod(this);
996     delete d_ptr;
997 }
998 
999 // ===============
1000 
~QtRuntimeMethodData()1001 QtRuntimeMethodData::~QtRuntimeMethodData()
1002 {
1003 }
1004 
~QtRuntimeMetaMethodData()1005 QtRuntimeMetaMethodData::~QtRuntimeMetaMethodData()
1006 {
1007 
1008 }
1009 
~QtRuntimeConnectionMethodData()1010 QtRuntimeConnectionMethodData::~QtRuntimeConnectionMethodData()
1011 {
1012 
1013 }
1014 
1015 // ===============
1016 
1017 // Type conversion metadata (from QtScript originally)
1018 class QtMethodMatchType
1019 {
1020 public:
1021     enum Kind {
1022         Invalid,
1023         Variant,
1024         MetaType,
1025         Unresolved,
1026         MetaEnum
1027     };
1028 
1029 
QtMethodMatchType()1030     QtMethodMatchType()
1031         : m_kind(Invalid) { }
1032 
kind() const1033     Kind kind() const
1034     { return m_kind; }
1035 
1036     QMetaType::Type typeId() const;
1037 
isValid() const1038     bool isValid() const
1039     { return (m_kind != Invalid); }
1040 
isVariant() const1041     bool isVariant() const
1042     { return (m_kind == Variant); }
1043 
isMetaType() const1044     bool isMetaType() const
1045     { return (m_kind == MetaType); }
1046 
isUnresolved() const1047     bool isUnresolved() const
1048     { return (m_kind == Unresolved); }
1049 
isMetaEnum() const1050     bool isMetaEnum() const
1051     { return (m_kind == MetaEnum); }
1052 
1053     QByteArray name() const;
1054 
enumeratorIndex() const1055     int enumeratorIndex() const
1056     { Q_ASSERT(isMetaEnum()); return m_typeId; }
1057 
variant()1058     static QtMethodMatchType variant()
1059     { return QtMethodMatchType(Variant); }
1060 
metaType(int typeId,const QByteArray & name)1061     static QtMethodMatchType metaType(int typeId, const QByteArray &name)
1062     { return QtMethodMatchType(MetaType, typeId, name); }
1063 
metaEnum(int enumIndex,const QByteArray & name)1064     static QtMethodMatchType metaEnum(int enumIndex, const QByteArray &name)
1065     { return QtMethodMatchType(MetaEnum, enumIndex, name); }
1066 
unresolved(const QByteArray & name)1067     static QtMethodMatchType unresolved(const QByteArray &name)
1068     { return QtMethodMatchType(Unresolved, /*typeId=*/0, name); }
1069 
1070 private:
QtMethodMatchType(Kind kind,int typeId=0,const QByteArray & name=QByteArray ())1071     QtMethodMatchType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
1072         : m_kind(kind), m_typeId(typeId), m_name(name) { }
1073 
1074     Kind m_kind;
1075     int m_typeId;
1076     QByteArray m_name;
1077 };
1078 
typeId() const1079 QMetaType::Type QtMethodMatchType::typeId() const
1080 {
1081     if (isVariant())
1082         return (QMetaType::Type) QMetaType::type("QVariant");
1083     return (QMetaType::Type) (isMetaEnum() ? QMetaType::Int : m_typeId);
1084 }
1085 
name() const1086 QByteArray QtMethodMatchType::name() const
1087 {
1088     if (!m_name.isEmpty())
1089         return m_name;
1090     else if (m_kind == Variant)
1091         return "QVariant";
1092     return QByteArray();
1093 }
1094 
1095 struct QtMethodMatchData
1096 {
1097     int matchDistance;
1098     int index;
1099     QVector<QtMethodMatchType> types;
1100     QVarLengthArray<QVariant, 10> args;
1101 
QtMethodMatchDataJSC::Bindings::QtMethodMatchData1102     QtMethodMatchData(int dist, int idx, QVector<QtMethodMatchType> typs,
1103                                 const QVarLengthArray<QVariant, 10> &as)
1104         : matchDistance(dist), index(idx), types(typs), args(as) { }
QtMethodMatchDataJSC::Bindings::QtMethodMatchData1105     QtMethodMatchData()
1106         : index(-1) { }
1107 
isValidJSC::Bindings::QtMethodMatchData1108     bool isValid() const
1109     { return (index != -1); }
1110 
firstUnresolvedIndexJSC::Bindings::QtMethodMatchData1111     int firstUnresolvedIndex() const
1112     {
1113         for (int i=0; i < types.count(); i++) {
1114             if (types.at(i).isUnresolved())
1115                 return i;
1116         }
1117         return -1;
1118     }
1119 };
1120 
indexOfMetaEnum(const QMetaObject * meta,const QByteArray & str)1121 static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
1122 {
1123     QByteArray scope;
1124     QByteArray name;
1125     int scopeIdx = str.indexOf("::");
1126     if (scopeIdx != -1) {
1127         scope = str.left(scopeIdx);
1128         name = str.mid(scopeIdx + 2);
1129     } else {
1130         name = str;
1131     }
1132     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
1133         QMetaEnum m = meta->enumerator(i);
1134         if ((m.name() == name)/* && (scope.isEmpty() || (m.scope() == scope))*/)
1135             return i;
1136     }
1137     return -1;
1138 }
1139 
1140 // Helper function for resolving methods
1141 // Largely based on code in QtScript for compatibility reasons
findMethodIndex(ExecState * exec,const QMetaObject * meta,const QByteArray & signature,bool allowPrivate,QVarLengthArray<QVariant,10> & vars,void ** vvars,JSObject ** pError)1142 static int findMethodIndex(ExecState* exec,
1143                            const QMetaObject* meta,
1144                            const QByteArray& signature,
1145                            bool allowPrivate,
1146                            QVarLengthArray<QVariant, 10> &vars,
1147                            void** vvars,
1148                            JSObject **pError)
1149 {
1150     QList<int> matchingIndices;
1151 
1152     bool overloads = !signature.contains('(');
1153 
1154     int count = meta->methodCount();
1155     for (int i = count - 1; i >= 0; --i) {
1156         const QMetaMethod m = meta->method(i);
1157 
1158         // Don't choose private methods
1159         if (m.access() == QMetaMethod::Private && !allowPrivate)
1160             continue;
1161 
1162         // try and find all matching named methods
1163         if (m.signature() == signature)
1164             matchingIndices.append(i);
1165         else if (overloads) {
1166             QByteArray rawsignature = m.signature();
1167             rawsignature.truncate(rawsignature.indexOf('('));
1168             if (rawsignature == signature)
1169                 matchingIndices.append(i);
1170         }
1171     }
1172 
1173     int chosenIndex = -1;
1174     *pError = 0;
1175     QVector<QtMethodMatchType> chosenTypes;
1176 
1177     QVarLengthArray<QVariant, 10> args;
1178     QVector<QtMethodMatchData> candidates;
1179     QVector<QtMethodMatchData> unresolved;
1180     QVector<int> tooFewArgs;
1181     QVector<int> conversionFailed;
1182 
1183     foreach(int index, matchingIndices) {
1184         QMetaMethod method = meta->method(index);
1185 
1186         QVector<QtMethodMatchType> types;
1187         bool unresolvedTypes = false;
1188 
1189         // resolve return type
1190         QByteArray returnTypeName = method.typeName();
1191         int rtype = QMetaType::type(returnTypeName);
1192         if ((rtype == 0) && !returnTypeName.isEmpty()) {
1193             if (returnTypeName == "QVariant") {
1194                 types.append(QtMethodMatchType::variant());
1195             } else if (returnTypeName.endsWith('*')) {
1196                 types.append(QtMethodMatchType::metaType(QMetaType::VoidStar, returnTypeName));
1197             } else {
1198                 int enumIndex = indexOfMetaEnum(meta, returnTypeName);
1199                 if (enumIndex != -1)
1200                     types.append(QtMethodMatchType::metaEnum(enumIndex, returnTypeName));
1201                 else {
1202                     unresolvedTypes = true;
1203                     types.append(QtMethodMatchType::unresolved(returnTypeName));
1204                 }
1205             }
1206         } else {
1207             if (returnTypeName == "QVariant")
1208                 types.append(QtMethodMatchType::variant());
1209             else
1210                 types.append(QtMethodMatchType::metaType(rtype, returnTypeName));
1211         }
1212 
1213         // resolve argument types
1214         QList<QByteArray> parameterTypeNames = method.parameterTypes();
1215         for (int i = 0; i < parameterTypeNames.count(); ++i) {
1216             QByteArray argTypeName = parameterTypeNames.at(i);
1217             int atype = QMetaType::type(argTypeName);
1218             if (atype == 0) {
1219                 if (argTypeName == "QVariant") {
1220                     types.append(QtMethodMatchType::variant());
1221                 } else {
1222                     int enumIndex = indexOfMetaEnum(meta, argTypeName);
1223                     if (enumIndex != -1)
1224                         types.append(QtMethodMatchType::metaEnum(enumIndex, argTypeName));
1225                     else {
1226                         unresolvedTypes = true;
1227                         types.append(QtMethodMatchType::unresolved(argTypeName));
1228                     }
1229                 }
1230             } else {
1231                 if (argTypeName == "QVariant")
1232                     types.append(QtMethodMatchType::variant());
1233                 else
1234                     types.append(QtMethodMatchType::metaType(atype, argTypeName));
1235             }
1236         }
1237 
1238         // If the native method requires more arguments than what was passed from JavaScript
1239         if (exec->argumentCount() + 1 < static_cast<unsigned>(types.count())) {
1240             qMatchDebug() << "Match:too few args for" << method.signature();
1241             tooFewArgs.append(index);
1242             continue;
1243         }
1244 
1245         if (unresolvedTypes) {
1246             qMatchDebug() << "Match:unresolved arg types for" << method.signature();
1247             // remember it so we can give an error message later, if necessary
1248             unresolved.append(QtMethodMatchData(/*matchDistance=*/INT_MAX, index,
1249                                                    types, QVarLengthArray<QVariant, 10>()));
1250             continue;
1251         }
1252 
1253         // Now convert arguments
1254         if (args.count() != types.count())
1255             args.resize(types.count());
1256 
1257         QtMethodMatchType retType = types[0];
1258         args[0] = QVariant(retType.typeId(), (void *)0); // the return value
1259 
1260         bool converted = true;
1261         int matchDistance = 0;
1262         for (unsigned i = 0; converted && i + 1 < static_cast<unsigned>(types.count()); ++i) {
1263             JSValue arg = i < exec->argumentCount() ? exec->argument(i) : jsUndefined();
1264 
1265             int argdistance = -1;
1266             QVariant v = convertValueToQVariant(exec, arg, types.at(i+1).typeId(), &argdistance);
1267             if (argdistance >= 0) {
1268                 matchDistance += argdistance;
1269                 args[i+1] = v;
1270             } else {
1271                 qMatchDebug() << "failed to convert argument " << i << "type" << types.at(i+1).typeId() << QMetaType::typeName(types.at(i+1).typeId());
1272                 converted = false;
1273             }
1274         }
1275 
1276         qMatchDebug() << "Match: " << method.signature() << (converted ? "converted":"failed to convert") << "distance " << matchDistance;
1277 
1278         if (converted) {
1279             if ((exec->argumentCount() + 1 == static_cast<unsigned>(types.count()))
1280                 && (matchDistance == 0)) {
1281                 // perfect match, use this one
1282                 chosenIndex = index;
1283                 break;
1284             } else {
1285                 QtMethodMatchData currentMatch(matchDistance, index, types, args);
1286                 if (candidates.isEmpty()) {
1287                     candidates.append(currentMatch);
1288                 } else {
1289                     QtMethodMatchData bestMatchSoFar = candidates.at(0);
1290                     if ((args.count() > bestMatchSoFar.args.count())
1291                         || ((args.count() == bestMatchSoFar.args.count())
1292                             && (matchDistance <= bestMatchSoFar.matchDistance))) {
1293                         candidates.prepend(currentMatch);
1294                     } else {
1295                         candidates.append(currentMatch);
1296                     }
1297                 }
1298             }
1299         } else {
1300             conversionFailed.append(index);
1301         }
1302 
1303         if (!overloads)
1304             break;
1305     }
1306 
1307     if (chosenIndex == -1 && candidates.count() == 0) {
1308         // No valid functions at all - format an error message
1309         if (!conversionFailed.isEmpty()) {
1310             QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
1311                               .arg(QLatin1String(signature));
1312             for (int i = 0; i < conversionFailed.size(); ++i) {
1313                 if (i > 0)
1314                     message += QLatin1String("\n");
1315                 QMetaMethod mtd = meta->method(conversionFailed.at(i));
1316                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
1317             }
1318             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1319         } else if (!unresolved.isEmpty()) {
1320             QtMethodMatchData argsInstance = unresolved.first();
1321             int unresolvedIndex = argsInstance.firstUnresolvedIndex();
1322             Q_ASSERT(unresolvedIndex != -1);
1323             QtMethodMatchType unresolvedType = argsInstance.types.at(unresolvedIndex);
1324             QString message = QString::fromLatin1("cannot call %0(): unknown type `%1'")
1325                 .arg(QString::fromLatin1(signature))
1326                 .arg(QLatin1String(unresolvedType.name()));
1327             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1328         } else {
1329             QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
1330                               .arg(QLatin1String(signature));
1331             for (int i = 0; i < tooFewArgs.size(); ++i) {
1332                 if (i > 0)
1333                     message += QLatin1String("\n");
1334                 QMetaMethod mtd = meta->method(tooFewArgs.at(i));
1335                 message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
1336             }
1337             *pError = throwError(exec, createSyntaxError(exec, message.toLatin1().constData()));
1338         }
1339     }
1340 
1341     if (chosenIndex == -1 && candidates.count() > 0) {
1342         QtMethodMatchData bestMatch = candidates.at(0);
1343         if ((candidates.size() > 1)
1344             && (bestMatch.args.count() == candidates.at(1).args.count())
1345             && (bestMatch.matchDistance == candidates.at(1).matchDistance)) {
1346             // ambiguous call
1347             QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
1348                                 .arg(QLatin1String(signature));
1349             for (int i = 0; i < candidates.size(); ++i) {
1350                 // Only candidate for overload if argument count and match distance is same as best match
1351                 if (candidates.at(i).args.count() == bestMatch.args.count()
1352                     || candidates.at(i).matchDistance == bestMatch.matchDistance) {
1353                     if (i > 0)
1354                         message += QLatin1String("\n");
1355                     QMetaMethod mtd = meta->method(candidates.at(i).index);
1356                     message += QString::fromLatin1("    %0").arg(QString::fromLatin1(mtd.signature()));
1357                 }
1358             }
1359             *pError = throwError(exec, createTypeError(exec, message.toLatin1().constData()));
1360         } else {
1361             chosenIndex = bestMatch.index;
1362             args = bestMatch.args;
1363         }
1364     }
1365 
1366     if (chosenIndex != -1) {
1367         /* Copy the stuff over */
1368         int i;
1369         vars.resize(args.count());
1370         for (i=0; i < args.count(); i++) {
1371             vars[i] = args[i];
1372             vvars[i] = vars[i].data();
1373         }
1374     }
1375 
1376     return chosenIndex;
1377 }
1378 
1379 // Signals are not fuzzy matched as much as methods
findSignalIndex(const QMetaObject * meta,int initialIndex,QByteArray signature)1380 static int findSignalIndex(const QMetaObject* meta, int initialIndex, QByteArray signature)
1381 {
1382     int index = initialIndex;
1383     QMetaMethod method = meta->method(index);
1384     bool overloads = !signature.contains('(');
1385     if (overloads && (method.attributes() & QMetaMethod::Cloned)) {
1386         // find the most general method
1387         do {
1388             method = meta->method(--index);
1389         } while (method.attributes() & QMetaMethod::Cloned);
1390     }
1391     return index;
1392 }
1393 
QtRuntimeMetaMethod(ExecState * exec,const Identifier & ident,PassRefPtr<QtInstance> inst,int index,const QByteArray & signature,bool allowPrivate)1394 QtRuntimeMetaMethod::QtRuntimeMetaMethod(ExecState* exec, const Identifier& ident, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature, bool allowPrivate)
1395     : QtRuntimeMethod (new QtRuntimeMetaMethodData(), exec, ident, inst)
1396 {
1397     QW_D(QtRuntimeMetaMethod);
1398     d->m_signature = signature;
1399     d->m_index = index;
1400     d->m_allowPrivate = allowPrivate;
1401 }
1402 
markChildren(MarkStack & markStack)1403 void QtRuntimeMetaMethod::markChildren(MarkStack& markStack)
1404 {
1405     QtRuntimeMethod::markChildren(markStack);
1406     QW_D(QtRuntimeMetaMethod);
1407     if (d->m_connect)
1408         markStack.append(&d->m_connect);
1409     if (d->m_disconnect)
1410         markStack.append(&d->m_disconnect);
1411 }
1412 
call(ExecState * exec)1413 EncodedJSValue QtRuntimeMetaMethod::call(ExecState* exec)
1414 {
1415     QtRuntimeMetaMethodData* d = static_cast<QtRuntimeMetaMethod *>(exec->callee())->d_func();
1416 
1417     // We're limited to 10 args
1418     if (exec->argumentCount() > 10)
1419         return JSValue::encode(jsUndefined());
1420 
1421     // We have to pick a method that matches..
1422     JSLock lock(SilenceAssertionsOnly);
1423 
1424     QObject *obj = d->m_instance->getObject();
1425     if (obj) {
1426         QVarLengthArray<QVariant, 10> vargs;
1427         void *qargs[11];
1428 
1429         int methodIndex;
1430         JSObject* errorObj = 0;
1431         if ((methodIndex = findMethodIndex(exec, obj->metaObject(), d->m_signature, d->m_allowPrivate, vargs, (void **)qargs, &errorObj)) != -1) {
1432             if (QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, methodIndex, qargs) >= 0)
1433                 return JSValue::encode(jsUndefined());
1434 
1435             if (vargs[0].isValid())
1436                 return JSValue::encode(convertQVariantToValue(exec, d->m_instance->rootObject(), vargs[0]));
1437         }
1438 
1439         if (errorObj)
1440             return JSValue::encode(errorObj);
1441     } else {
1442         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
1443     }
1444 
1445     // void functions return undefined
1446     return JSValue::encode(jsUndefined());
1447 }
1448 
getCallData(CallData & callData)1449 CallType QtRuntimeMetaMethod::getCallData(CallData& callData)
1450 {
1451     callData.native.function = call;
1452     return CallTypeHost;
1453 }
1454 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)1455 bool QtRuntimeMetaMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1456 {
1457     if (propertyName == "connect") {
1458         slot.setCustom(this, connectGetter);
1459         return true;
1460     } else if (propertyName == "disconnect") {
1461         slot.setCustom(this, disconnectGetter);
1462         return true;
1463     } else if (propertyName == exec->propertyNames().length) {
1464         slot.setCustom(this, lengthGetter);
1465         return true;
1466     }
1467 
1468     return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
1469 }
1470 
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)1471 bool QtRuntimeMetaMethod::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
1472 {
1473     if (propertyName == "connect") {
1474         PropertySlot slot;
1475         slot.setCustom(this, connectGetter);
1476         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1477         return true;
1478     }
1479 
1480     if (propertyName == "disconnect") {
1481         PropertySlot slot;
1482         slot.setCustom(this, disconnectGetter);
1483         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1484         return true;
1485     }
1486 
1487     if (propertyName == exec->propertyNames().length) {
1488         PropertySlot slot;
1489         slot.setCustom(this, lengthGetter);
1490         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1491         return true;
1492     }
1493 
1494     return QtRuntimeMethod::getOwnPropertyDescriptor(exec, propertyName, descriptor);
1495 }
1496 
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)1497 void QtRuntimeMetaMethod::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1498 {
1499     if (mode == IncludeDontEnumProperties) {
1500         propertyNames.add(Identifier(exec, "connect"));
1501         propertyNames.add(Identifier(exec, "disconnect"));
1502         propertyNames.add(exec->propertyNames().length);
1503     }
1504 
1505     QtRuntimeMethod::getOwnPropertyNames(exec, propertyNames, mode);
1506 }
1507 
lengthGetter(ExecState *,JSValue,const Identifier &)1508 JSValue QtRuntimeMetaMethod::lengthGetter(ExecState*, JSValue, const Identifier&)
1509 {
1510     // QtScript always returns 0
1511     return jsNumber(0);
1512 }
1513 
connectGetter(ExecState * exec,JSValue slotBase,const Identifier & ident)1514 JSValue QtRuntimeMetaMethod::connectGetter(ExecState* exec, JSValue slotBase, const Identifier& ident)
1515 {
1516     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
1517     QW_DS(QtRuntimeMetaMethod, thisObj);
1518 
1519     if (!d->m_connect)
1520         d->m_connect.set(exec->globalData(), thisObj, new (exec) QtRuntimeConnectionMethod(exec, ident, true, d->m_instance, d->m_index, d->m_signature));
1521     return d->m_connect.get();
1522 }
1523 
disconnectGetter(ExecState * exec,JSValue slotBase,const Identifier & ident)1524 JSValue QtRuntimeMetaMethod::disconnectGetter(ExecState* exec, JSValue slotBase, const Identifier& ident)
1525 {
1526     QtRuntimeMetaMethod* thisObj = static_cast<QtRuntimeMetaMethod*>(asObject(slotBase));
1527     QW_DS(QtRuntimeMetaMethod, thisObj);
1528 
1529     if (!d->m_disconnect)
1530         d->m_disconnect.set(exec->globalData(), thisObj, new (exec) QtRuntimeConnectionMethod(exec, ident, false, d->m_instance, d->m_index, d->m_signature));
1531     return d->m_disconnect.get();
1532 }
1533 
1534 // ===============
1535 
1536 QMultiMap<QObject*, QtConnectionObject*> QtRuntimeConnectionMethod::connections;
1537 
QtRuntimeConnectionMethod(ExecState * exec,const Identifier & ident,bool isConnect,PassRefPtr<QtInstance> inst,int index,const QByteArray & signature)1538 QtRuntimeConnectionMethod::QtRuntimeConnectionMethod(ExecState* exec, const Identifier& ident, bool isConnect, PassRefPtr<QtInstance> inst, int index, const QByteArray& signature)
1539     : QtRuntimeMethod (new QtRuntimeConnectionMethodData(), exec, ident, inst)
1540 {
1541     QW_D(QtRuntimeConnectionMethod);
1542 
1543     d->m_signature = signature;
1544     d->m_index = index;
1545     d->m_isConnect = isConnect;
1546 }
1547 
call(ExecState * exec)1548 EncodedJSValue QtRuntimeConnectionMethod::call(ExecState* exec)
1549 {
1550     QtRuntimeConnectionMethodData* d = static_cast<QtRuntimeConnectionMethod *>(exec->callee())->d_func();
1551 
1552     JSLock lock(SilenceAssertionsOnly);
1553 
1554     QObject* sender = d->m_instance->getObject();
1555 
1556     if (sender) {
1557 
1558         JSObject* thisObject = exec->lexicalGlobalObject();
1559         JSObject* funcObject = 0;
1560 
1561         // QtScript checks signalness first, arguments second
1562         int signalIndex = -1;
1563 
1564         // Make sure the initial index is a signal
1565         QMetaMethod m = sender->metaObject()->method(d->m_index);
1566         if (m.methodType() == QMetaMethod::Signal)
1567             signalIndex = findSignalIndex(sender->metaObject(), d->m_index, d->m_signature);
1568 
1569         if (signalIndex != -1) {
1570             if (exec->argumentCount() == 1) {
1571                 funcObject = exec->argument(0).toObject(exec);
1572                 CallData callData;
1573                 if (funcObject->getCallData(callData) == CallTypeNone) {
1574                     if (d->m_isConnect)
1575                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
1576                     else
1577                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
1578                 }
1579             } else if (exec->argumentCount() >= 2) {
1580                 if (exec->argument(0).isObject()) {
1581                     thisObject = exec->argument(0).toObject(exec);
1582 
1583                     // Get the actual function to call
1584                     JSObject *asObj = exec->argument(1).toObject(exec);
1585                     CallData callData;
1586                     if (asObj->getCallData(callData) != CallTypeNone) {
1587                         // Function version
1588                         funcObject = asObj;
1589                     } else {
1590                         // Convert it to a string
1591                         UString funcName = exec->argument(1).toString(exec);
1592                         Identifier funcIdent(exec, funcName);
1593 
1594                         // ### DropAllLocks
1595                         // This is resolved at this point in QtScript
1596                         JSValue val = thisObject->get(exec, funcIdent);
1597                         JSObject* asFuncObj = val.toObject(exec);
1598 
1599                         if (asFuncObj->getCallData(callData) != CallTypeNone) {
1600                             funcObject = asFuncObj;
1601                         } else {
1602                             if (d->m_isConnect)
1603                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: target is not a function"));
1604                             else
1605                                 return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: target is not a function"));
1606                         }
1607                     }
1608                 } else {
1609                     if (d->m_isConnect)
1610                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.connect: thisObject is not an object"));
1611                     else
1612                         return throwVMError(exec, createTypeError(exec, "QtMetaMethod.disconnect: thisObject is not an object"));
1613                 }
1614             } else {
1615                 if (d->m_isConnect)
1616                     return throwVMError(exec, createError(exec, "QtMetaMethod.connect: no arguments given"));
1617                 else
1618                     return throwVMError(exec, createError(exec, "QtMetaMethod.disconnect: no arguments given"));
1619             }
1620 
1621             if (d->m_isConnect) {
1622                 // to connect, we need:
1623                 //  target object [from ctor]
1624                 //  target signal index etc. [from ctor]
1625                 //  receiver function [from arguments]
1626                 //  receiver this object [from arguments]
1627 
1628                 QtConnectionObject* conn = new QtConnectionObject(exec->globalData(), d->m_instance, signalIndex, thisObject, funcObject);
1629                 bool ok = QMetaObject::connect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1630                 if (!ok) {
1631                     delete conn;
1632                     QString msg = QString(QLatin1String("QtMetaMethod.connect: failed to connect to %1::%2()"))
1633                             .arg(QLatin1String(sender->metaObject()->className()))
1634                             .arg(QLatin1String(d->m_signature));
1635                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
1636                 }
1637                 else {
1638                     // Store connection
1639                     connections.insert(sender, conn);
1640                 }
1641             } else {
1642                 // Now to find our previous connection object. Hmm.
1643                 QList<QtConnectionObject*> conns = connections.values(sender);
1644                 bool ret = false;
1645 
1646                 foreach(QtConnectionObject* conn, conns) {
1647                     // Is this the right connection?
1648                     if (conn->match(sender, signalIndex, thisObject, funcObject)) {
1649                         // Yep, disconnect it
1650                         QMetaObject::disconnect(sender, signalIndex, conn, conn->metaObject()->methodOffset());
1651                         delete conn; // this will also remove it from the map
1652                         ret = true;
1653                         break;
1654                     }
1655                 }
1656 
1657                 if (!ret) {
1658                     QString msg = QString(QLatin1String("QtMetaMethod.disconnect: failed to disconnect from %1::%2()"))
1659                             .arg(QLatin1String(sender->metaObject()->className()))
1660                             .arg(QLatin1String(d->m_signature));
1661                     return throwVMError(exec, createError(exec, msg.toLatin1().constData()));
1662                 }
1663             }
1664         } else {
1665             QString msg = QString(QLatin1String("QtMetaMethod.%1: %2::%3() is not a signal"))
1666                     .arg(QLatin1String(d->m_isConnect ? "connect": "disconnect"))
1667                     .arg(QLatin1String(sender->metaObject()->className()))
1668                     .arg(QLatin1String(d->m_signature));
1669             return throwVMError(exec, createTypeError(exec, msg.toLatin1().constData()));
1670         }
1671     } else {
1672         return throwVMError(exec, createError(exec, "cannot call function of deleted QObject"));
1673     }
1674 
1675     return JSValue::encode(jsUndefined());
1676 }
1677 
getCallData(CallData & callData)1678 CallType QtRuntimeConnectionMethod::getCallData(CallData& callData)
1679 {
1680     callData.native.function = call;
1681     return CallTypeHost;
1682 }
1683 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)1684 bool QtRuntimeConnectionMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
1685 {
1686     if (propertyName == exec->propertyNames().length) {
1687         slot.setCustom(this, lengthGetter);
1688         return true;
1689     }
1690 
1691     return QtRuntimeMethod::getOwnPropertySlot(exec, propertyName, slot);
1692 }
1693 
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)1694 bool QtRuntimeConnectionMethod::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
1695 {
1696     if (propertyName == exec->propertyNames().length) {
1697         PropertySlot slot;
1698         slot.setCustom(this, lengthGetter);
1699         descriptor.setDescriptor(slot.getValue(exec, propertyName), DontDelete | ReadOnly | DontEnum);
1700         return true;
1701     }
1702 
1703     return QtRuntimeMethod::getOwnPropertyDescriptor(exec, propertyName, descriptor);
1704 }
1705 
getOwnPropertyNames(ExecState * exec,PropertyNameArray & propertyNames,EnumerationMode mode)1706 void QtRuntimeConnectionMethod::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
1707 {
1708     if (mode == IncludeDontEnumProperties)
1709         propertyNames.add(exec->propertyNames().length);
1710 
1711     QtRuntimeMethod::getOwnPropertyNames(exec, propertyNames, mode);
1712 }
1713 
lengthGetter(ExecState *,JSValue,const Identifier &)1714 JSValue QtRuntimeConnectionMethod::lengthGetter(ExecState*, JSValue, const Identifier&)
1715 {
1716     // we have one formal argument, and one optional
1717     return jsNumber(1);
1718 }
1719 
1720 // ===============
1721 
QtConnectionObject(JSGlobalData & globalData,PassRefPtr<QtInstance> instance,int signalIndex,JSObject * thisObject,JSObject * funcObject)1722 QtConnectionObject::QtConnectionObject(JSGlobalData& globalData, PassRefPtr<QtInstance> instance, int signalIndex, JSObject* thisObject, JSObject* funcObject)
1723     : m_instance(instance)
1724     , m_signalIndex(signalIndex)
1725     , m_originalObject(m_instance->getObject())
1726     , m_thisObject(globalData, thisObject)
1727     , m_funcObject(globalData, funcObject)
1728 {
1729     setParent(m_originalObject);
1730     ASSERT(JSLock::currentThreadIsHoldingLock()); // so our ProtectedPtrs are safe
1731 }
1732 
~QtConnectionObject()1733 QtConnectionObject::~QtConnectionObject()
1734 {
1735     // Remove us from the map of active connections
1736     QtRuntimeConnectionMethod::connections.remove(m_originalObject, this);
1737 }
1738 
1739 static const uint qt_meta_data_QtConnectionObject[] = {
1740 
1741  // content:
1742        1,       // revision
1743        0,       // classname
1744        0,    0, // classinfo
1745        1,   10, // methods
1746        0,    0, // properties
1747        0,    0, // enums/sets
1748 
1749  // slots: signature, parameters, type, tag, flags
1750       28,   27,   27,   27, 0x0a,
1751 
1752        0        // eod
1753 };
1754 
1755 static const char qt_meta_stringdata_QtConnectionObject[] = {
1756     "JSC::Bindings::QtConnectionObject\0\0execute()\0"
1757 };
1758 
1759 const QMetaObject QtConnectionObject::staticMetaObject = {
1760     { &QObject::staticMetaObject, qt_meta_stringdata_QtConnectionObject,
1761       qt_meta_data_QtConnectionObject, 0 }
1762 };
1763 
metaObject() const1764 const QMetaObject *QtConnectionObject::metaObject() const
1765 {
1766     return &staticMetaObject;
1767 }
1768 
qt_metacast(const char * _clname)1769 void *QtConnectionObject::qt_metacast(const char *_clname)
1770 {
1771     if (!_clname) return 0;
1772     if (!strcmp(_clname, qt_meta_stringdata_QtConnectionObject))
1773         return static_cast<void*>(const_cast<QtConnectionObject*>(this));
1774     return QObject::qt_metacast(_clname);
1775 }
1776 
qt_metacall(QMetaObject::Call _c,int _id,void ** _a)1777 int QtConnectionObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
1778 {
1779     _id = QObject::qt_metacall(_c, _id, _a);
1780     if (_id < 0)
1781         return _id;
1782     if (_c == QMetaObject::InvokeMetaMethod) {
1783         switch (_id) {
1784         case 0: execute(_a); break;
1785         }
1786         _id -= 1;
1787     }
1788     return _id;
1789 }
1790 
execute(void ** argv)1791 void QtConnectionObject::execute(void **argv)
1792 {
1793     QObject* obj = m_instance->getObject();
1794     if (obj) {
1795         const QMetaObject* meta = obj->metaObject();
1796         const QMetaMethod method = meta->method(m_signalIndex);
1797 
1798         QList<QByteArray> parameterTypes = method.parameterTypes();
1799 
1800         int argc = parameterTypes.count();
1801 
1802         JSLock lock(SilenceAssertionsOnly);
1803 
1804         // ### Should the Interpreter/ExecState come from somewhere else?
1805         RefPtr<RootObject> ro = m_instance->rootObject();
1806         if (ro) {
1807             JSGlobalObject* globalobj = ro->globalObject();
1808             if (globalobj) {
1809                 ExecState* exec = globalobj->globalExec();
1810                 if (exec) {
1811                     // Build the argument list (up to the formal argument length of the slot)
1812                     MarkedArgumentBuffer l;
1813                     // ### DropAllLocks?
1814                     int funcArgC = m_funcObject->get(exec, exec->propertyNames().length).toInt32(exec);
1815                     int argTotal = qMax(funcArgC, argc);
1816                     for(int i=0; i < argTotal; i++) {
1817                         if (i < argc) {
1818                             int argType = QMetaType::type(parameterTypes.at(i));
1819                             l.append(convertQVariantToValue(exec, ro, QVariant(argType, argv[i+1])));
1820                         } else {
1821                             l.append(jsUndefined());
1822                         }
1823                     }
1824                     // Stuff in the __qt_sender property, if we can
1825                     ScopeChainNode* oldsc = 0;
1826                     JSFunction* fimp = 0;
1827                     if (m_funcObject->inherits(&JSFunction::s_info)) {
1828                         fimp = static_cast<JSFunction*>(m_funcObject.get());
1829 
1830                         JSObject* qt_sender = QtInstance::getQtInstance(sender(), ro, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
1831                         JSObject* wrapper = constructEmptyObject(exec, createEmptyObjectStructure(exec->globalData(), jsNull()));
1832                         PutPropertySlot slot;
1833                         wrapper->put(exec, Identifier(exec, "__qt_sender__"), qt_sender, slot);
1834                         oldsc = fimp->scope();
1835                         fimp->setScope(exec->globalData(), oldsc->push(wrapper));
1836                     }
1837 
1838                     CallData callData;
1839                     CallType callType = m_funcObject->getCallData(callData);
1840                     call(exec, m_funcObject.get(), callType, callData, m_thisObject.get(), l);
1841 
1842                     if (fimp)
1843                         fimp->setScope(exec->globalData(), oldsc);
1844                 }
1845             }
1846         }
1847     } else {
1848         // A strange place to be - a deleted object emitted a signal here.
1849         qWarning() << "sender deleted, cannot deliver signal";
1850     }
1851 }
1852 
match(QObject * sender,int signalIndex,JSObject * thisObject,JSObject * funcObject)1853 bool QtConnectionObject::match(QObject* sender, int signalIndex, JSObject* thisObject, JSObject *funcObject)
1854 {
1855     if (m_originalObject == sender && m_signalIndex == signalIndex
1856         && thisObject == (JSObject*)m_thisObject.get() && funcObject == (JSObject*)m_funcObject.get())
1857         return true;
1858     return false;
1859 }
1860 
1861 // ===============
1862 
QtArray(QList<T> list,QMetaType::Type type,PassRefPtr<RootObject> rootObject)1863 template <typename T> QtArray<T>::QtArray(QList<T> list, QMetaType::Type type, PassRefPtr<RootObject> rootObject)
1864     : Array(rootObject)
1865     , m_list(list)
1866     , m_type(type)
1867 {
1868     m_length = m_list.count();
1869 }
1870 
~QtArray()1871 template <typename T> QtArray<T>::~QtArray ()
1872 {
1873 }
1874 
rootObject() const1875 template <typename T> RootObject* QtArray<T>::rootObject() const
1876 {
1877     return m_rootObject && m_rootObject->isValid() ? m_rootObject.get() : 0;
1878 }
1879 
setValueAt(ExecState * exec,unsigned index,JSValue aValue) const1880 template <typename T> void QtArray<T>::setValueAt(ExecState* exec, unsigned index, JSValue aValue) const
1881 {
1882     // QtScript sets the value, but doesn't forward it to the original source
1883     // (e.g. if you do 'object.intList[5] = 6', the object is not updated, but the
1884     // copy of the list is).
1885     int dist = -1;
1886     QVariant val = convertValueToQVariant(exec, aValue, m_type, &dist);
1887 
1888     if (dist >= 0) {
1889         m_list[index] = val.value<T>();
1890     }
1891 }
1892 
1893 
valueAt(ExecState * exec,unsigned int index) const1894 template <typename T> JSValue QtArray<T>::valueAt(ExecState *exec, unsigned int index) const
1895 {
1896     if (index < m_length) {
1897         T val = m_list.at(index);
1898         return convertQVariantToValue(exec, rootObject(), QVariant::fromValue(val));
1899     }
1900 
1901     return jsUndefined();
1902 }
1903 
1904 // ===============
1905 
1906 } }
1907