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