Adapt to Qt5 meta-object changes
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qqmlpropertycache_p.h"
43
44 #include "qqmlengine_p.h"
45 #include "qqmlbinding_p.h"
46 #include <private/qv8engine_p.h>
47
48 #include <private/qmetaobject_p.h>
49 #include <private/qqmlaccessors_p.h>
50
51 #include <QtCore/qdebug.h>
52
53 #include <ctype.h> // for toupper
54
55 Q_DECLARE_METATYPE(QJSValue)
56 Q_DECLARE_METATYPE(QQmlV8Handle);
57
58 QT_BEGIN_NAMESPACE
59
60 #define Q_INT16_MAX 32767
61
62 class QQmlPropertyCacheMethodArguments 
63 {
64 public:
65     QQmlPropertyCacheMethodArguments *next;
66     int arguments[0];
67 };
68
69 // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
70 // to load
71 static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
72 {
73     QQmlPropertyData::Flags flags;
74
75     if (p.isConstant())
76         flags |= QQmlPropertyData::IsConstant;
77     if (p.isWritable())
78         flags |= QQmlPropertyData::IsWritable;
79     if (p.isResettable())
80         flags |= QQmlPropertyData::IsResettable;
81     if (p.isFinal())
82         flags |= QQmlPropertyData::IsFinal;
83     if (p.isEnumType())
84         flags |= QQmlPropertyData::IsEnumType;
85
86     return flags;
87 }
88
89 // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to 
90 // load
91 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
92 {
93     Q_ASSERT(propType != -1);
94
95     QQmlPropertyData::Flags flags;
96
97     if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
98         flags |= QQmlPropertyData::IsQObjectDerived;
99     } else if (propType == QMetaType::QVariant) {
100         flags |= QQmlPropertyData::IsQVariant;
101     } else if (propType < (int)QVariant::UserType) {
102     } else if (propType == qMetaTypeId<QQmlBinding *>()) {
103         flags |= QQmlPropertyData::IsQmlBinding;
104     } else if (propType == qMetaTypeId<QJSValue>()) {
105         flags |= QQmlPropertyData::IsQJSValue;
106     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
107         flags |= QQmlPropertyData::IsV8Handle;
108     } else {
109         QQmlMetaType::TypeCategory cat = 
110             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
111                    : QQmlMetaType::typeCategory(propType);
112
113         if (cat == QQmlMetaType::Object)
114             flags |= QQmlPropertyData::IsQObjectDerived;
115         else if (cat == QQmlMetaType::List)
116             flags |= QQmlPropertyData::IsQList;
117     }
118
119     return flags;
120 }
121
122 static int metaObjectSignalCount(const QMetaObject *metaObject)
123 {
124     int signalCount = 0;
125     for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
126         signalCount += QMetaObjectPrivate::get(obj)->signalCount;
127     return signalCount;
128 }
129
130 QQmlPropertyData::Flags
131 QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
132 {
133     return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
134 }
135
136 void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
137 {
138     Q_UNUSED(engine);
139
140     coreIndex = p.propertyIndex();
141     notifyIndex = p.notifySignalIndex();
142     Q_ASSERT(p.revision() <= Q_INT16_MAX);
143     revision = p.revision();
144
145     flags = fastFlagsForProperty(p);
146
147     int type = p.type();
148     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
149         propType = type;
150         flags |= QQmlPropertyData::IsQObjectDerived;
151     } else if (type == QMetaType::QVariant) {
152         propType = type;
153         flags |= QQmlPropertyData::IsQVariant;
154     } else if (type == QVariant::UserType || type == -1) {
155         propTypeName = p.typeName();
156         flags |= QQmlPropertyData::NotFullyResolved;
157     } else {
158         propType = type;
159     }
160 }
161
162 void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
163 {
164     propType = p.userType();
165     coreIndex = p.propertyIndex();
166     notifyIndex = p.notifySignalIndex();
167     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
168     Q_ASSERT(p.revision() <= Q_INT16_MAX);
169     revision = p.revision();
170 }
171
172 void QQmlPropertyData::load(const QMetaMethod &m)
173 {
174     coreIndex = m.methodIndex();
175     arguments = 0;
176     flags |= IsFunction;
177     if (m.methodType() == QMetaMethod::Signal)
178         flags |= IsSignal;
179     propType = m.returnType();
180
181     if (m.parameterCount()) {
182         flags |= HasArguments;
183         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
184             flags |= IsV8Function;
185         }
186     }
187
188     Q_ASSERT(m.revision() <= Q_INT16_MAX);
189     revision = m.revision();
190 }
191
192 void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
193 {
194     coreIndex = m.methodIndex();
195     arguments = 0;
196     flags |= IsFunction;
197     if (m.methodType() == QMetaMethod::Signal)
198         flags |= IsSignal;
199     propType = QVariant::Invalid;
200
201     const char *returnType = m.typeName();
202     if (returnType && *returnType) {
203         propTypeName = returnType;
204         flags |= NotFullyResolved;
205     }
206
207     if (m.parameterCount()) {
208         flags |= HasArguments;
209         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
210             flags |= IsV8Function;
211         }
212     }
213
214     Q_ASSERT(m.revision() <= Q_INT16_MAX);
215     revision = m.revision();
216 }
217
218 /*!
219 Creates a new empty QQmlPropertyCache.
220 */
221 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
222 : engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
223   signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
224 {
225     Q_ASSERT(engine);
226 }
227
228 /*!
229 Creates a new QQmlPropertyCache of \a metaObject.
230 */
231 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
232 : engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
233   signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
234 {
235     Q_ASSERT(engine);
236     Q_ASSERT(metaObject);
237
238     update(engine, metaObject);
239 }
240
241 QQmlPropertyCache::~QQmlPropertyCache()
242 {
243     clear();
244
245     QQmlPropertyCacheMethodArguments *args = argumentsCache;
246     while (args) {
247         QQmlPropertyCacheMethodArguments *next = args->next;
248         free(args);
249         args = next;
250     }
251
252     // We must clear this prior to releasing the parent incase it is a
253     // linked hash
254     stringCache.clear();
255     if (parent) parent->release();
256     parent = 0;
257     engine = 0;
258 }
259
260 void QQmlPropertyCache::destroy()
261 {
262     Q_ASSERT(engine || constructor.IsEmpty());
263     if (constructor.IsEmpty())
264         delete this;
265     else
266         QQmlEnginePrivate::deleteInEngineThread(engine, this);
267 }
268
269 // This is inherited from QQmlCleanup, so it should only clear the things
270 // that are tied to the specific QQmlEngine.
271 void QQmlPropertyCache::clear()
272 {
273     qPersistentDispose(constructor);
274     engine = 0;
275 }
276
277 QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
278 {
279     QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
280     cache->parent = this;
281     cache->parent->addref();
282     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
283     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
284     cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart;
285     cache->stringCache.linkAndReserve(stringCache, reserve);
286     cache->allowedRevisionCache = allowedRevisionCache;
287     cache->metaObject = metaObject;
288
289     // We specifically do *NOT* copy the constructor
290
291     return cache;
292 }
293
294 QQmlPropertyCache *QQmlPropertyCache::copy()
295 {
296     return copy(0);
297 }
298
299 QQmlPropertyCache *
300 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
301                                          QQmlPropertyData::Flag propertyFlags,
302                                          QQmlPropertyData::Flag methodFlags,
303                                          QQmlPropertyData::Flag signalFlags)
304 {
305     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
306 }
307
308 QQmlPropertyCache *
309 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
310                                          int revision,
311                                          QQmlPropertyData::Flag propertyFlags,
312                                          QQmlPropertyData::Flag methodFlags,
313                                          QQmlPropertyData::Flag signalFlags)
314 {
315     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
316
317     // Reserve enough space in the name hash for all the methods (including signals), all the
318     // signal handlers and all the properties.  This assumes no name clashes, but this is the
319     // common case.
320     QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
321                                          QMetaObjectPrivate::get(metaObject)->signalCount +
322                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
323
324     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
325
326     return rv;
327 }
328
329 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
330                                        QQmlPropertyData::Flag propertyFlags,
331                                        QQmlPropertyData::Flag methodFlags,
332                                        QQmlPropertyData::Flag signalFlags)
333 {
334     append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
335 }
336
337 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
338                                        int revision, 
339                                        QQmlPropertyData::Flag propertyFlags,
340                                        QQmlPropertyData::Flag methodFlags,
341                                        QQmlPropertyData::Flag signalFlags)
342 {
343     Q_UNUSED(revision);
344     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
345
346     this->metaObject = metaObject;
347
348     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
349
350     allowedRevisionCache.append(0);
351
352     int methodCount = metaObject->methodCount();
353     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
354     int signalCount = metaObjectSignalCount(metaObject);
355     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
356
357     QQmlAccessorProperties::Properties accessorProperties;
358
359     // Special case QObject as we don't want to add a qt_HasQmlAccessors classinfo to it
360     if (metaObject == &QObject::staticMetaObject) {
361         accessorProperties = QQmlAccessorProperties::properties(metaObject);
362     } else if (classInfoCount) {
363         int classInfoOffset = metaObject->classInfoOffset();
364         bool hasFastProperty = false;
365         for (int ii = 0; ii < classInfoCount; ++ii) {
366             int idx = ii + classInfoOffset;
367
368             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
369                 hasFastProperty = true;
370                 break;
371             }
372         }
373
374         if (hasFastProperty) {
375             accessorProperties = QQmlAccessorProperties::properties(metaObject);
376             if (accessorProperties.count == 0)
377                 qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
378                        "installed property accessors", metaObject->className());
379         } else {
380 #ifndef QT_NO_DEBUG
381             accessorProperties = QQmlAccessorProperties::properties(metaObject);
382             if (accessorProperties.count != 0)
383                 qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
384                        "FastProperty class info", metaObject->className());
385 #endif
386         }
387     }
388
389     // qMax(defaultMethods, methodOffset) to block the signals and slots of QObject::staticMetaObject
390     // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
391     int methodOffset = qMax(QObject::staticMetaObject.methodCount(), metaObject->methodOffset());
392     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
393
394     // update() should have reserved enough space in the vector that this doesn't cause a realloc
395     // and invalidate the stringCache.
396     methodIndexCache.resize(methodCount - methodIndexCacheStart);
397     signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart);
398     int signalHandlerIndex = signalOffset;
399     for (int ii = methodOffset; ii < methodCount; ++ii) {
400         QMetaMethod m = metaObject->method(ii);
401         if (m.access() == QMetaMethod::Private) 
402             continue;
403
404         // Extract method name
405         const char *signature;
406         if (QMetaObjectPrivate::get(metaObject)->revision >= 7) {
407             // Safe to use the raw name pointer
408             signature = m.name().constData();
409         } else {
410             // Safe to use the raw signature pointer
411             signature = m.methodSignature().constData();
412         }
413         const char *cptr = signature;
414         char utf8 = 0;
415         while (*cptr && *cptr != '(') {
416             Q_ASSERT(*cptr != 0);
417             utf8 |= *cptr & 0x80;
418             ++cptr;
419         }
420
421         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
422         QQmlPropertyData *sigdata = 0;
423
424         data->lazyLoad(m);
425
426         if (data->isSignal())
427             data->flags |= signalFlags;
428         else
429             data->flags |= methodFlags;
430
431         if (!dynamicMetaObject)
432             data->flags |= QQmlPropertyData::IsDirect;
433
434         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
435         data->metaObjectOffset = allowedRevisionCache.count() - 1;
436
437         if (data->isSignal()) {
438             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart];
439             *sigdata = *data;
440             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
441         }
442
443         QQmlPropertyData *old = 0;
444
445         if (utf8) {
446             QHashedString methodName(QString::fromUtf8(signature, cptr - signature));
447             if (QQmlPropertyData **it = stringCache.value(methodName))
448                 old = *it;
449             stringCache.insert(methodName, data);
450
451             if (data->isSignal()) {
452                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
453                 stringCache.insert(on, sigdata);
454                 ++signalHandlerIndex;
455             }
456         } else {
457             QHashedCStringRef methodName(signature, cptr - signature);
458             if (QQmlPropertyData **it = stringCache.value(methodName))
459                 old = *it;
460             stringCache.insert(methodName, data);
461
462             if (data->isSignal()) {
463                 int length = methodName.length();
464
465                 QVarLengthArray<char, 128> str(length+3);
466                 str[0] = 'o';
467                 str[1] = 'n';
468                 str[2] = toupper(signature[0]);
469                 if (length > 1)
470                     memcpy(&str[3], &signature[1], length - 1);
471                 str[length + 2] = '\0';
472
473                 QHashedString on(QString::fromLatin1(str.data()));
474                 stringCache.insert(on, sigdata);
475                 ++signalHandlerIndex;
476             }
477         }
478
479         if (old) {
480             // We only overload methods in the same class, exactly like C++
481             if (old->isFunction() && old->coreIndex >= methodOffset)
482                 data->flags |= QQmlPropertyData::IsOverload;
483             data->overrideIndexIsProperty = !old->isFunction();
484             data->overrideIndex = old->coreIndex;
485         }
486     }
487
488     int propCount = metaObject->propertyCount();
489     int propOffset = metaObject->propertyOffset();
490
491     // update() should have reserved enough space in the vector that this doesn't cause a realloc
492     // and invalidate the stringCache.
493     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
494     for (int ii = propOffset; ii < propCount; ++ii) {
495         QMetaProperty p = metaObject->property(ii);
496         if (!p.isScriptable())
497             continue;
498
499         const char *str = p.name();
500         char utf8 = 0;
501         const char *cptr = str;
502         while (*cptr != 0) {
503             utf8 |= *cptr & 0x80;
504             ++cptr;
505         }
506
507         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
508
509         data->lazyLoad(p, engine);
510         data->flags |= propertyFlags;
511
512         if (!dynamicMetaObject) 
513             data->flags |= QQmlPropertyData::IsDirect;
514
515         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
516         data->metaObjectOffset = allowedRevisionCache.count() - 1;
517
518         QQmlPropertyData *old = 0;
519
520         if (utf8) {
521             QHashedString propName(QString::fromUtf8(str, cptr - str));
522             if (QQmlPropertyData **it = stringCache.value(propName))
523                 old = *it;
524             stringCache.insert(propName, data);
525         } else {
526             QHashedCStringRef propName(str, cptr - str);
527             if (QQmlPropertyData **it = stringCache.value(propName))
528                 old = *it;
529             stringCache.insert(propName, data);
530         }
531
532         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
533
534         // Fast properties may not be overrides or revisioned
535         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
536
537         if (accessorProperty) {
538             data->flags |= QQmlPropertyData::HasAccessors;
539             data->accessors = accessorProperty->accessors;
540             data->accessorData = accessorProperty->data;
541         } else if (old) {
542             data->overrideIndexIsProperty = !old->isFunction();
543             data->overrideIndex = old->coreIndex;
544         }
545     }
546 }
547
548 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
549 {
550     Q_ASSERT(data->notFullyResolved());
551
552     data->propType = QMetaType::type(data->propTypeName);
553
554     if (!data->isFunction())
555         data->flags |= flagsForPropertyType(data->propType, engine);
556
557     data->flags &= ~QQmlPropertyData::NotFullyResolved;
558 }
559
560 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
561 {
562     if (!metaObject)
563         return;
564
565     updateRecur(engine, metaObject->superClass());
566
567     append(engine, metaObject);
568 }
569
570 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
571 {
572     Q_ASSERT(engine);
573     Q_ASSERT(metaObject);
574     Q_ASSERT(stringCache.isEmpty());
575
576     // Preallocate enough space in the index caches for all the properties/methods/signals that
577     // are not cached in a parent cache so that the caches never need to be reallocated as this
578     // would invalidate pointers stored in the stringCache.
579     int pc = metaObject->propertyCount();
580     int mc = metaObject->methodCount();
581     int sc = metaObjectSignalCount(metaObject);
582     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
583     methodIndexCache.reserve(mc - methodIndexCacheStart);
584     signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart);
585
586     // Reserve enough space in the stringCache for all properties/methods/signals including those
587     // cached in a parent cache.
588     stringCache.reserve(pc + mc + sc);
589
590     updateRecur(engine,metaObject);
591 }
592
593 QQmlPropertyData *
594 QQmlPropertyCache::property(int index) const
595 {
596     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
597         return 0;
598     
599     if (index < propertyIndexCacheStart)
600         return parent->property(index);
601
602     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
603     if (rv->notFullyResolved()) resolve(rv);
604     return rv;
605 }
606
607 QQmlPropertyData *
608 QQmlPropertyCache::method(int index) const
609 {
610     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
611         return 0;
612
613     if (index < methodIndexCacheStart)
614         return parent->method(index);
615
616     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
617     if (rv->notFullyResolved()) resolve(rv);
618     return rv;
619 }
620
621 QQmlPropertyData *
622 QQmlPropertyCache::property(const QHashedStringRef &str) const
623 {
624     QQmlPropertyData **rv = stringCache.value(str);
625     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
626     return rv?*rv:0;
627 }
628
629 QQmlPropertyData *
630 QQmlPropertyCache::property(const QHashedCStringRef &str) const
631 {
632     QQmlPropertyData **rv = stringCache.value(str);
633     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
634     return rv?*rv:0;
635 }
636
637 QQmlPropertyData *
638 QQmlPropertyCache::property(const QString &str) const
639 {
640     QQmlPropertyData **rv = stringCache.value(str);
641     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
642     return rv?*rv:0;
643 }
644
645 QString QQmlPropertyData::name(QObject *object)
646 {
647     if (!object)
648         return QString();
649
650     return name(object->metaObject());
651 }
652
653 QString QQmlPropertyData::name(const QMetaObject *metaObject)
654 {
655     if (!metaObject || coreIndex == -1)
656         return QString();
657
658     if (flags & IsFunction) {
659         QMetaMethod m = metaObject->method(coreIndex);
660
661         return QString::fromUtf8(m.name().constData());
662     } else {
663         QMetaProperty p = metaObject->property(coreIndex);
664         return QString::fromUtf8(p.name());
665     }
666 }
667
668 QStringList QQmlPropertyCache::propertyNames() const
669 {
670     QStringList keys;
671     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
672         keys.append(iter.key());
673     return keys;
674 }
675
676 static int EnumType(const QMetaObject *meta, const QByteArray &str)
677 {
678     QByteArray scope;
679     QByteArray name;
680     int scopeIdx = str.lastIndexOf("::");
681     if (scopeIdx != -1) {
682         scope = str.left(scopeIdx);
683         name = str.mid(scopeIdx + 2);
684     } else { 
685         name = str;
686     }
687     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
688         QMetaEnum m = meta->enumerator(i);
689         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
690             return QVariant::Int;
691     }
692     return QVariant::Invalid;
693 }
694
695 // Returns an array of the arguments for method \a index.  The first entry in the array
696 // is the number of arguments.
697 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
698                                                      QVarLengthArray<int, 9> &dummy,
699                                                      QByteArray *unknownTypeError)
700 {
701     Q_ASSERT(object && index >= 0);
702
703     QQmlData *ddata = QQmlData::get(object, false);
704
705     if (ddata && ddata->propertyCache) {
706         typedef QQmlPropertyCacheMethodArguments A;
707
708         QQmlPropertyCache *c = ddata->propertyCache;
709         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
710
711         while (index < c->methodIndexCacheStart)
712             c = c->parent;
713
714         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
715
716         if (rv->arguments)  
717             return static_cast<A *>(rv->arguments)->arguments;
718
719         const QMetaObject *metaObject = object->metaObject();
720         QMetaMethod m = metaObject->method(index);
721
722         int argc = m.parameterCount();
723         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
724         args->arguments[0] = argc;
725         QList<QByteArray> argTypeNames; // Only loaded if needed
726
727         for (int ii = 0; ii < argc; ++ii) {
728             int type = m.parameterType(ii);
729             if (type == QVariant::Invalid) {
730                 if (argTypeNames.isEmpty())
731                     argTypeNames = m.parameterTypes();
732                 type = EnumType(object->metaObject(), argTypeNames.at(ii));
733             }
734             if (type == QVariant::Invalid) {
735                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
736                 free(args);
737                 return 0;
738             }
739             args->arguments[ii + 1] = type;
740         }
741
742         rv->arguments = args;
743         args->next = c->argumentsCache;
744         c->argumentsCache = args;
745         return static_cast<A *>(rv->arguments)->arguments;
746
747     } else {
748         QMetaMethod m = object->metaObject()->method(index);
749         int argc = m.parameterCount();
750         dummy.resize(argc + 1);
751         dummy[0] = argc;
752         QList<QByteArray> argTypeNames; // Only loaded if needed
753
754         for (int ii = 0; ii < argc; ++ii) {
755             int type = m.parameterType(ii);
756             if (type == QVariant::Invalid) {
757                 if (argTypeNames.isEmpty())
758                     argTypeNames = m.parameterTypes();
759                 type = EnumType(object->metaObject(), argTypeNames.at(ii));
760             }
761             if (type == QVariant::Invalid) {
762                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
763                 return 0;
764             }
765             dummy[ii + 1] = type;
766         }
767
768         return dummy.data();
769     }
770 }
771
772 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject,
773                                                          const QString &property)
774 {
775     Q_ASSERT(metaObject);
776
777     QQmlPropertyData rv;
778     {
779         const QMetaObject *cmo = metaObject;
780         const QByteArray propertyName = property.toUtf8();
781         while (cmo) {
782             int idx = cmo->indexOfProperty(propertyName);
783             if (idx != -1) {
784                 QMetaProperty p = cmo->property(idx);
785                 if (p.isScriptable()) {
786                     rv.load(p);
787                     return rv;
788                 } else {
789                     while (cmo && cmo->propertyOffset() >= idx)
790                         cmo = cmo->superClass();
791                 }
792             } else {
793                 cmo = 0;
794             }
795         }
796     }
797
798     int methodCount = metaObject->methodCount();
799     int defaultMethods = QObject::staticMetaObject.methodCount();
800     for (int ii = methodCount - 1; ii >= defaultMethods; --ii) {
801         // >=defaultMethods to block the signals and slots of QObject::staticMetaObject
802         // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
803         QMetaMethod m = metaObject->method(ii);
804         if (m.access() == QMetaMethod::Private)
805             continue;
806         QString methodName = QString::fromUtf8(m.name().constData());
807
808         if (methodName == property) {
809             rv.load(m);
810             return rv;
811         }
812     }
813
814     return rv;
815 }
816
817 inline const QString &qQmlPropertyCacheToString(const QString &string)
818 {
819     return string;
820 }
821
822 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
823 {
824     return QV8Engine::toStringStatic(string.string());
825 }
826
827 template<typename T>
828 QQmlPropertyData *
829 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj,
830                                   const T &name, QQmlPropertyData &local)
831 {
832     QQmlPropertyCache *cache = 0;
833
834     if (engine) {
835         QQmlData *ddata = QQmlData::get(obj);
836
837         if (ddata && ddata->propertyCache) {
838             cache = ddata->propertyCache;
839         } else if (engine) {
840             QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
841             cache = ep->cache(obj);
842             if (cache) {
843                 ddata = QQmlData::get(obj, true);
844                 cache->addref();
845                 ddata->propertyCache = cache;
846             }
847         }
848     }
849
850     QQmlPropertyData *rv = 0;
851
852     if (cache) {
853         rv = cache->property(name);
854     } else {
855         local = qQmlPropertyCacheCreate(obj->metaObject(),
856                                                 qQmlPropertyCacheToString(name));
857         if (local.isValid())
858             rv = &local;
859     }
860
861     return rv;
862 }
863
864 QQmlPropertyData *
865 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
866                                     const QHashedV8String &name, QQmlPropertyData &local)
867 {
868     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
869 }
870
871 QQmlPropertyData *
872 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
873                                     const QString &name, QQmlPropertyData &local)
874 {
875     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
876 }
877
878 static inline const QMetaObjectPrivate *priv(const uint* data)
879 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
880
881 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
882 {
883     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
884 }
885
886 QT_END_NAMESPACE