PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/platform/external/webkit/WebCore/bridge/qt/qt_runtime.cpp

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